package com.gitee.jmash.rbac.grpc;

import com.alipay.api.response.AlipaySystemOauthTokenResponse;
import com.alipay.api.response.AlipayUserInfoShareResponse;
import com.gitee.jmash.captcha.client.cdi.CaptchaClient;
import com.gitee.jmash.common.config.VerifyCodeProps;
import com.gitee.jmash.common.event.SafeEvent;
import com.gitee.jmash.common.grpc.GrpcContext;
import com.gitee.jmash.common.security.JmashPrincipal;
import com.gitee.jmash.common.tree.Tree;
import com.gitee.jmash.common.utils.UUIDUtil;
import com.gitee.jmash.common.utils.VersionUtil;
import com.gitee.jmash.core.grpc.cdi.GrpcService;
import com.gitee.jmash.core.grpc.utils.ThrowUtil;
import com.gitee.jmash.core.jaxrs.ParamsValidationException;
import com.gitee.jmash.core.lib.ProtoEnumUtil;
import com.gitee.jmash.core.orm.DtoPage;
import com.gitee.jmash.core.orm.DtoTotal;
import com.gitee.jmash.core.utils.FileServiceUtil;
import com.gitee.jmash.core.utils.TenantUtil;
import com.gitee.jmash.rbac.RbacFactory;
import com.gitee.jmash.rbac.RbacMapper;
import com.gitee.jmash.rbac.client.token.OrganUserAccessToken;
import com.gitee.jmash.rbac.entity.DeptEntity;
import com.gitee.jmash.rbac.entity.LogEntity;
import com.gitee.jmash.rbac.entity.LogEntity.LogPk;
import com.gitee.jmash.rbac.entity.ModuleEntity;
import com.gitee.jmash.rbac.entity.OpenAppEntity;
import com.gitee.jmash.rbac.entity.OpensEntity;
import com.gitee.jmash.rbac.entity.OpensEntity.OpensPk;
import com.gitee.jmash.rbac.entity.OperationEntity;
import com.gitee.jmash.rbac.entity.PermEntity;
import com.gitee.jmash.rbac.entity.ResourceEntity;
import com.gitee.jmash.rbac.entity.RoleEntity;
import com.gitee.jmash.rbac.entity.RolesDutyEntity;
import com.gitee.jmash.rbac.entity.TokenEntity;
import com.gitee.jmash.rbac.entity.UserEntity;
import com.gitee.jmash.rbac.entity.UserLogEntity;
import com.gitee.jmash.rbac.entity.UserLogEntity.UserLogPk;
import com.gitee.jmash.rbac.exception.JmashAuthenticationException;
import com.gitee.jmash.rbac.mapper.DeptMapper;
import com.gitee.jmash.rbac.mapper.LogMapper;
import com.gitee.jmash.rbac.mapper.ModuleMapper;
import com.gitee.jmash.rbac.mapper.OpenAppMapper;
import com.gitee.jmash.rbac.mapper.OpensMapper;
import com.gitee.jmash.rbac.mapper.OperationMapper;
import com.gitee.jmash.rbac.mapper.PermMapper;
import com.gitee.jmash.rbac.mapper.ResourceMapper;
import com.gitee.jmash.rbac.mapper.RoleMapper;
import com.gitee.jmash.rbac.mapper.UserLogMapper;
import com.gitee.jmash.rbac.mapper.UserMapper;
import com.gitee.jmash.rbac.model.ResourcePermResult;
import com.gitee.jmash.rbac.model.TreeResult;
import com.gitee.jmash.rbac.model.UserOpenCreateReq;
import com.gitee.jmash.rbac.service.DeptRead;
import com.gitee.jmash.rbac.service.DeptWrite;
import com.gitee.jmash.rbac.service.LogRead;
import com.gitee.jmash.rbac.service.LogWrite;
import com.gitee.jmash.rbac.service.ModuleRead;
import com.gitee.jmash.rbac.service.ModuleWrite;
import com.gitee.jmash.rbac.service.OpenAppRead;
import com.gitee.jmash.rbac.service.OpenAppWrite;
import com.gitee.jmash.rbac.service.OpensRead;
import com.gitee.jmash.rbac.service.OperationRead;
import com.gitee.jmash.rbac.service.OperationWrite;
import com.gitee.jmash.rbac.service.PermRead;
import com.gitee.jmash.rbac.service.PermWrite;
import com.gitee.jmash.rbac.service.ResourceRead;
import com.gitee.jmash.rbac.service.ResourceWrite;
import com.gitee.jmash.rbac.service.RoleRead;
import com.gitee.jmash.rbac.service.RoleWrite;
import com.gitee.jmash.rbac.service.UserLogRead;
import com.gitee.jmash.rbac.service.UserLogWrite;
import com.gitee.jmash.rbac.service.UserRead;
import com.gitee.jmash.rbac.service.UserWrite;
import com.gitee.jmash.rbac.thirdparty.alipay.AlipayUtil;
import com.gitee.jmash.rbac.thirdparty.unionpay.UnionPayService;
import com.gitee.jmash.rbac.thirdparty.unionpay.model.UnionTokenResp;
import com.gitee.jmash.rbac.thirdparty.unionpay.model.UnionUserMobile;
import com.gitee.jmash.rbac.utils.AuthzUtil;
import com.gitee.jmash.rbac.utils.MiniappUtil;
import com.gitee.jmash.rbac.utils.MobileAppUtil;
import com.gitee.jmash.rbac.utils.PermUtils;
import com.gitee.jmash.rbac.utils.RunAsUtil;
import com.gitee.jmash.rbac.utils.VerifyCodeUtil;
import com.gitee.jmash.storage.client.StorageClient;
import com.google.api.HttpBody;
import com.google.protobuf.BoolValue;
import com.google.protobuf.Empty;
import com.google.protobuf.EnumValue;
import com.google.protobuf.Int32Value;
import com.google.protobuf.StringValue;
import com.xyvcard.wechat.client.WechatClient;
import com.xyvcard.weixin.auth.api.OauthWechatClient;
import com.xyvcard.weixin.wechat.model.MiniLoginResp;
import com.xyvcard.weixin.wechat.model.PhoneInfo;
import io.grpc.Status;
import io.grpc.stub.StreamObserver;
import jakarta.enterprise.event.Event;
import jakarta.inject.Inject;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.stream.Collectors;
import jmash.captcha.protobuf.CaptchaReq;
import jmash.protobuf.CustomEnumValue;
import jmash.protobuf.CustomEnumValueMap;
import jmash.protobuf.Entry;
import jmash.protobuf.EntryList;
import jmash.protobuf.EnumEntryReq;
import jmash.protobuf.EnumValueList;
import jmash.protobuf.TenantReq;
import jmash.protobuf.TreeList;
import jmash.rbac.protobuf.AppendRolePermReq;
import jmash.rbac.protobuf.ApprovedUserReq;
import jmash.rbac.protobuf.ChangePhoneEmailReq;
import jmash.rbac.protobuf.ChangePwdReq;
import jmash.rbac.protobuf.ChangeWechatBindReq;
import jmash.rbac.protobuf.DeptCountUpdateReq;
import jmash.rbac.protobuf.DeptCreateReq;
import jmash.rbac.protobuf.DeptEnableKey;
import jmash.rbac.protobuf.DeptExportReq;
import jmash.rbac.protobuf.DeptImportReq;
import jmash.rbac.protobuf.DeptKey;
import jmash.rbac.protobuf.DeptKeyList;
import jmash.rbac.protobuf.DeptList;
import jmash.rbac.protobuf.DeptModel;
import jmash.rbac.protobuf.DeptMoveKey;
import jmash.rbac.protobuf.DeptReq;
import jmash.rbac.protobuf.DeptUpdateReq;
import jmash.rbac.protobuf.DirectoryListResp;
import jmash.rbac.protobuf.DsdRoleListResp;
import jmash.rbac.protobuf.EnableDeptReq;
import jmash.rbac.protobuf.EnableUserReq;
import jmash.rbac.protobuf.ForgotPwdReq;
import jmash.rbac.protobuf.GzhSubscribeCheckReq;
import jmash.rbac.protobuf.LockUserReq;
import jmash.rbac.protobuf.LogDelReq;
import jmash.rbac.protobuf.LogExportReq;
import jmash.rbac.protobuf.LogKey;
import jmash.rbac.protobuf.LogList;
import jmash.rbac.protobuf.LogModel;
import jmash.rbac.protobuf.LogPage;
import jmash.rbac.protobuf.LogReq;
import jmash.rbac.protobuf.LoginAliAuthReq;
import jmash.rbac.protobuf.LoginAliRegisterReq;
import jmash.rbac.protobuf.LoginAppReq;
import jmash.rbac.protobuf.LoginGzhAuthReq;
import jmash.rbac.protobuf.LoginGzhAuthResp;
import jmash.rbac.protobuf.LoginGzhAuthUrlReq;
import jmash.rbac.protobuf.LoginGzhRegisterReq;
import jmash.rbac.protobuf.LoginGzhRegisterResp;
import jmash.rbac.protobuf.LoginQrcodeReq;
import jmash.rbac.protobuf.LoginReq;
import jmash.rbac.protobuf.LoginTokenResp;
import jmash.rbac.protobuf.LoginUnionPayRegisterReq;
import jmash.rbac.protobuf.LoginUnionPayReq;
import jmash.rbac.protobuf.LogoutReq;
import jmash.rbac.protobuf.MenuList;
import jmash.rbac.protobuf.MiniAppBindPhoneReq;
import jmash.rbac.protobuf.MiniAppLoginReq;
import jmash.rbac.protobuf.MiniAppLoginResp;
import jmash.rbac.protobuf.MiniAppPhoneNumberReq;
import jmash.rbac.protobuf.MobileAppLoginBindPhoneReq;
import jmash.rbac.protobuf.MobileAppLoginReq;
import jmash.rbac.protobuf.MobileAppLoginResp;
import jmash.rbac.protobuf.ModuleCheck;
import jmash.rbac.protobuf.ModuleCreateReq;
import jmash.rbac.protobuf.ModuleKey;
import jmash.rbac.protobuf.ModuleKeyList;
import jmash.rbac.protobuf.ModuleList;
import jmash.rbac.protobuf.ModuleModel;
import jmash.rbac.protobuf.ModuleMoveKey;
import jmash.rbac.protobuf.ModulePage;
import jmash.rbac.protobuf.ModuleReq;
import jmash.rbac.protobuf.ModuleUpdateReq;
import jmash.rbac.protobuf.OpenAppCreateReq;
import jmash.rbac.protobuf.OpenAppKey;
import jmash.rbac.protobuf.OpenAppKeyList;
import jmash.rbac.protobuf.OpenAppList;
import jmash.rbac.protobuf.OpenAppModel;
import jmash.rbac.protobuf.OpenAppPage;
import jmash.rbac.protobuf.OpenAppReq;
import jmash.rbac.protobuf.OpenAppUpdateReq;
import jmash.rbac.protobuf.OpensKey;
import jmash.rbac.protobuf.OpensList;
import jmash.rbac.protobuf.OpensModel;
import jmash.rbac.protobuf.OpensReq;
import jmash.rbac.protobuf.OpensType;
import jmash.rbac.protobuf.OperationCheck;
import jmash.rbac.protobuf.OperationCreateReq;
import jmash.rbac.protobuf.OperationKey;
import jmash.rbac.protobuf.OperationKeyList;
import jmash.rbac.protobuf.OperationList;
import jmash.rbac.protobuf.OperationModel;
import jmash.rbac.protobuf.OperationMoveKey;
import jmash.rbac.protobuf.OperationPage;
import jmash.rbac.protobuf.OperationReq;
import jmash.rbac.protobuf.OperationUpdateReq;
import jmash.rbac.protobuf.OrganUserAddReq;
import jmash.rbac.protobuf.OrganUserCreateReq;
import jmash.rbac.protobuf.PermCheck;
import jmash.rbac.protobuf.PermCreateReq;
import jmash.rbac.protobuf.PermKey;
import jmash.rbac.protobuf.PermKeyList;
import jmash.rbac.protobuf.PermList;
import jmash.rbac.protobuf.PermModel;
import jmash.rbac.protobuf.PermPage;
import jmash.rbac.protobuf.PermReq;
import jmash.rbac.protobuf.PermUpdateReq;
import jmash.rbac.protobuf.RefreshTokenReq;
import jmash.rbac.protobuf.RegisterUserReq;
import jmash.rbac.protobuf.ResourceCreateReq;
import jmash.rbac.protobuf.ResourceExportReq;
import jmash.rbac.protobuf.ResourceImportReq;
import jmash.rbac.protobuf.ResourceKey;
import jmash.rbac.protobuf.ResourceKeyList;
import jmash.rbac.protobuf.ResourceList;
import jmash.rbac.protobuf.ResourceModel;
import jmash.rbac.protobuf.ResourceMoveKey;
import jmash.rbac.protobuf.ResourcePermList;
import jmash.rbac.protobuf.ResourceReq;
import jmash.rbac.protobuf.ResourceUpdateReq;
import jmash.rbac.protobuf.RoleCreateReq;
import jmash.rbac.protobuf.RoleDetailReq;
import jmash.rbac.protobuf.RoleKey;
import jmash.rbac.protobuf.RoleKeyList;
import jmash.rbac.protobuf.RoleList;
import jmash.rbac.protobuf.RoleModel;
import jmash.rbac.protobuf.RoleMoveKey;
import jmash.rbac.protobuf.RolePermReq;
import jmash.rbac.protobuf.RolePermSet;
import jmash.rbac.protobuf.RoleReq;
import jmash.rbac.protobuf.RoleUpdateReq;
import jmash.rbac.protobuf.RunAsReq;
import jmash.rbac.protobuf.ScanCodeCreateUserReq;
import jmash.rbac.protobuf.SendValidCodeReq;
import jmash.rbac.protobuf.TokenResp;
import jmash.rbac.protobuf.UnionIdList;
import jmash.rbac.protobuf.UpdateUserReq;
import jmash.rbac.protobuf.UserCreateReq;
import jmash.rbac.protobuf.UserDeptJobInfoRes;
import jmash.rbac.protobuf.UserEnableKey;
import jmash.rbac.protobuf.UserExportReq;
import jmash.rbac.protobuf.UserImportReq;
import jmash.rbac.protobuf.UserInfo;
import jmash.rbac.protobuf.UserInfoList;
import jmash.rbac.protobuf.UserInfoPage;
import jmash.rbac.protobuf.UserKey;
import jmash.rbac.protobuf.UserKeyList;
import jmash.rbac.protobuf.UserList;
import jmash.rbac.protobuf.UserLogDelReq;
import jmash.rbac.protobuf.UserLogExportReq;
import jmash.rbac.protobuf.UserLogKey;
import jmash.rbac.protobuf.UserLogList;
import jmash.rbac.protobuf.UserLogModel;
import jmash.rbac.protobuf.UserLogPage;
import jmash.rbac.protobuf.UserLogReq;
import jmash.rbac.protobuf.UserModel;
import jmash.rbac.protobuf.UserNameReq;
import jmash.rbac.protobuf.UserOpensReq;
import jmash.rbac.protobuf.UserPage;
import jmash.rbac.protobuf.UserReq;
import jmash.rbac.protobuf.UserResetPwdReq;
import jmash.rbac.protobuf.UserRoleReq;
import jmash.rbac.protobuf.UserStatus;
import jmash.rbac.protobuf.UserUpdateReq;
import jmash.rbac.protobuf.ValidCodeLoginReq;
import jmash.rbac.protobuf.VerifyResourceReq;
import jmash.rbac.protobuf.VerifyRoleReq;
import jmash.rbac.protobuf.VerifyUserReq;
import jmash.storage.protobuf.StorageOrganUserCreateReq;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.shiro.authz.annotation.Logical;
import org.apache.shiro.authz.annotation.RequiresAuthentication;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.apache.shiro.subject.Subject;
import org.eclipse.microprofile.config.inject.ConfigProperties;
import xyvcard.wechat.protobuf.MobileAppUserOpenIdResp;
import xyvcard.wechat.protobuf.OauthCodeReq;
import xyvcard.wechat.protobuf.OauthUserInfoResp;
import xyvcard.wechat.protobuf.OauthUserOpenIdResp;

@GrpcService
public class RbacImpl extends jmash.rbac.RbacGrpc.RbacImplBase {

  // 模块版本
  public static final String version = "v1.0.0";
  private static Log log = LogFactory.getLog(RbacImpl.class);
  @Inject
  @ConfigProperties
  VerifyCodeProps verifyCodeProps;

  /**
   * 安全日志.
   */
  @Inject
  Event<SafeEvent> event;
  @Inject
  UnionPayService unionPayService;


  @Override
  public void version(Empty request, StreamObserver<StringValue> responseObserver) {
    responseObserver.onNext(StringValue.of(version + "-" + VersionUtil.snapshot(RbacImpl.class)));
    responseObserver.onCompleted();
  }

  @Override
  public void findEnumList(StringValue request, StreamObserver<EnumValueList> responseObserver) {
    try {
      List<EnumValue> list = ProtoEnumUtil.getEnumList(request.getValue());
      responseObserver.onNext(EnumValueList.newBuilder().addAllValues(list).build());
      responseObserver.onCompleted();
    } catch (Exception ex) {
      ThrowUtil.onError(log, responseObserver, ex);
    }
  }

  @Override
  public void findEnumMap(StringValue request,
      StreamObserver<CustomEnumValueMap> responseObserver) {
    try {
      Map<Integer, CustomEnumValue> values = ProtoEnumUtil.getEnumMap(request.getValue());
      responseObserver.onNext(CustomEnumValueMap.newBuilder().putAllValues(values).build());
      responseObserver.onCompleted();
    } catch (Exception ex) {
      ThrowUtil.onError(log, responseObserver, ex);
    }
  }

  @Override
  public void findEnumEntry(EnumEntryReq request, StreamObserver<EntryList> responseObserver) {
    try {
      List<Entry> entryList =
          ProtoEnumUtil.getEnumCodeList(request.getClassName(), request.getType());
      responseObserver.onNext(EntryList.newBuilder().addAllValues(entryList).build());
      responseObserver.onCompleted();
    } catch (Exception ex) {
      ThrowUtil.onError(log, responseObserver, ex);
    }
  }

  @Override
  public void sendValidCode(SendValidCodeReq request, StreamObserver<BoolValue> responseObserver) {
    try (UserRead userRead = RbacFactory.getUserRead(request.getTenant())) {
      // 1.先判断图形验证码是否正确
      if (verifyCodeProps.getEnable()) {
        CaptchaReq captchaReq = CaptchaReq.newBuilder().setCaptchaCode(request.getCaptchaCode())
            .setCaptchaId(request.getCaptchaId()).build();
        BoolValue valid = CaptchaClient.getCaptchaBlockingStub().validate(captchaReq);
        if (!valid.getValue()) {
          throw new ParamsValidationException("captchaCode", "验证码输入错误,请重新输入!");
        }
      }
      // 2.验证手机号或邮箱是否存在.
      if (!request.getSendValidCode()) {
        VerifyUserReq req = VerifyUserReq.newBuilder().setDirectoryId(request.getDirectoryId())
            .setTenant(request.getTenant()).setUserName(request.getName()).build();
        if (userRead.existUserName(req)) {
          throw new ParamsValidationException("name", "用户名已存在!");
        }
      }
      // 3.给用户发送验证码
      boolean success = VerifyCodeUtil.createVerifyCode(request.getTenant(), request.getName(), 6,
          request.getProduct());
      responseObserver.onNext(BoolValue.of(success));
      responseObserver.onCompleted();
    } catch (Exception ex) {
      ThrowUtil.onError(log, responseObserver, ex);
    }
  }

  @Override
  public void login(LoginReq req, StreamObserver<TokenResp> responseObserver) {
    // 用户登录.
    try (RoleRead roleRead = RbacFactory.getRoleRead(req.getTenant());
        UserWrite userWrite = RbacFactory.getUserWrite(req.getTenant())) {
      // 是否启用验证码.
      if (verifyCodeProps.getEnable() && StringUtils.isNotBlank(req.getCaptchaCode())) {
        CaptchaReq captchaReq = CaptchaReq.newBuilder().setCaptchaCode(req.getCaptchaCode())
            .setCaptchaId(req.getCaptchaId()).build();
        BoolValue valid = CaptchaClient.getCaptchaBlockingStub().validate(captchaReq);
        if (!valid.getValue()) {
          throw new ParamsValidationException("captchaCode", "验证码输入错误,请重新输入!");
        }
      }
      // 非系统角色，必须输入验证码.
      if (StringUtils.isBlank(req.getCaptchaCode())
          && !roleRead.checkSystemRole(req.getDirectoryId(), req.getUserName())) {
        throw new ParamsValidationException("captchaCode", "验证码不能为空,请输入验证码(测试环境配置system角色)!");
      }
      TokenEntity tokenEntity = userWrite.login(req);
      TokenResp resp = RbacMapper.INSTANCE.model(tokenEntity);
      responseObserver.onNext(resp);
      responseObserver.onCompleted();
    } catch (Exception ex) {
      ThrowUtil.onError(log, responseObserver, ex);
    }
  }

  @Override
  public void loginByQrcode(LoginQrcodeReq request, StreamObserver<TokenResp> responseObserver) {
    try (UserWrite userWrite = RbacFactory.getUserWrite(request.getTenant())) {
      TokenEntity tokenEntity = userWrite.loginByQrcode(request);
      TokenResp resp = RbacMapper.INSTANCE.model(tokenEntity);
      responseObserver.onNext(resp);
      responseObserver.onCompleted();
    } catch (Exception ex) {
      ThrowUtil.onError(log, responseObserver, ex);
    }
  }

  @Override
  public void loginByValidCode(ValidCodeLoginReq request,
      StreamObserver<TokenResp> responseObserver) {
    try (UserWrite userWrite = RbacFactory.getUserWrite(request.getTenant())) {
      TokenEntity tokenEntity = userWrite.loginByValidCode(request);
      TokenResp resp = RbacMapper.INSTANCE.model(tokenEntity);
      responseObserver.onNext(resp);
      responseObserver.onCompleted();
    } catch (Exception ex) {
      ThrowUtil.onError(log, responseObserver, ex);
    }
  }

  /**
   * 登录选择动态互斥角色,无需权限.
   */
  @Override
  public void selectDsdRoles(TenantReq request, StreamObserver<DsdRoleListResp> responseObserver) {
    try (RoleRead roleRead = RbacFactory.getRoleRead(request.getTenant())) {
      List<RoleEntity> roleEntityList = roleRead.getDsdRoleList();
      DsdRoleListResp resp = RoleMapper.INSTANCE.getDsdRoleList(roleEntityList);
      responseObserver.onNext(resp);
      responseObserver.onCompleted();
    } catch (Exception ex) {
      ThrowUtil.onError(log, responseObserver, ex);
    }
  }

  @Override
  public void logout(LogoutReq req, StreamObserver<BoolValue> responseObserver) {
    try (UserWrite userWrite = RbacFactory.getUserWrite(req.getTenant())) {
      Subject subject = (Subject) GrpcContext.USER_SUBJECT.get();
      if (subject != null && subject.isAuthenticated()) {
        subject.logout();
      } else {
        log.warn("登出没有提供Authorization信息，不能完全退出系统。");
      }
      // 登出组织
      JmashPrincipal principal = GrpcContext.getPrincipal();
      if (null != principal) {
        OrganUserAccessToken.clearOriginAccessToken(principal.getUnifiedId());
      }
      // 登出Token
      boolean success = userWrite.logout(req);
      responseObserver.onNext(BoolValue.of(success));
      responseObserver.onCompleted();
    } catch (Exception ex) {
      ThrowUtil.onError(log, responseObserver, ex);
    }
  }

  @Override
  public void refreshToken(RefreshTokenReq req, StreamObserver<TokenResp> responseObserver) {
    try (UserWrite userWrite = RbacFactory.getUserWrite(req.getTenant())) {
      TokenEntity tokenEntity = userWrite.refreshToken(req, false);
      TokenResp resp = RbacMapper.INSTANCE.model(tokenEntity);
      responseObserver.onNext(resp);
      responseObserver.onCompleted();
    } catch (Exception ex) {
      log.error("", ex);
      responseObserver
          .onError(Status.UNAUTHENTICATED.withDescription(ex.getMessage()).asException());
    }
  }

  @Override
  @RequiresAuthentication
  public void userInfo(TenantReq req, StreamObserver<UserModel> responseObserver) {
    try (UserRead userRead = RbacFactory.getUserRead(req.getTenant())) {
      JmashPrincipal principal = GrpcContext.getPrincipal();
      UserModel user = userRead.findUserById(principal.getNameUUID());
      responseObserver.onNext(user);
      responseObserver.onCompleted();
    } catch (Exception ex) {
      ThrowUtil.onError(log, responseObserver, ex);
    }
  }

  @Override
  @RequiresAuthentication
  public void updateUserInfo(UpdateUserReq request, StreamObserver<UserModel> responseObserver) {
    try (UserWrite userWrite = RbacFactory.getUserWrite(request.getTenant())) {
      JmashPrincipal principal = GrpcContext.getPrincipal();
      UserEntity user = userWrite.updateUser(request, principal.getName());
      UserModel model = UserMapper.INSTANCE.model(user);
      // 标记运行用户.
      model = RunAsUtil.markRunAsInfo(model);
      responseObserver.onNext(model);
      responseObserver.onCompleted();
    } catch (Exception ex) {
      ThrowUtil.onError(log, responseObserver, ex);
    }
  }

  @Override
  @RequiresAuthentication
  public void userMenus(TenantReq request, StreamObserver<MenuList> responseObserver) {
    try (ResourceRead resourceRead = RbacFactory.getResourceRead(request.getTenant())) {
      Tree<ResourceEntity, UUID> list = resourceRead
          .findTreeByReq(ResourceReq.newBuilder().setTenant(request.getTenant()).build());
      // 权限检查
      list = AuthzUtil.userMenuResource(list);
      MenuList modelList = ResourceMapper.INSTANCE.listMenu(list);
      responseObserver.onNext(modelList);
      responseObserver.onCompleted();
    } catch (Exception ex) {
      ThrowUtil.onError(log, responseObserver, ex);
    }
  }

  // 无需权限.
  @Override
  public void selectDirectoryIds(TenantReq request,
      StreamObserver<DirectoryListResp> responseObserver) {
    try (UserRead read = RbacFactory.getUserRead(request.getTenant())) {
      List<String> directoryIds = read.findDirectoryIds();
      DirectoryListResp directoryList =
          DirectoryListResp.newBuilder().addAllDirectoryId(directoryIds).build();
      responseObserver.onNext(directoryList);
      responseObserver.onCompleted();
    } catch (Exception ex) {
      ThrowUtil.onError(log, responseObserver, ex);
    }
  }

  @Override
  @RequiresAuthentication
  public void userRolesPerms(TenantReq request, StreamObserver<RolePermSet> responseObserver) {
    try {
      JmashPrincipal principal = GrpcContext.getPrincipal();
      RolePermSet rolePermSet = AuthzUtil.userRolesPerms(request.getTenant(), principal);
      responseObserver.onNext(rolePermSet);
      responseObserver.onCompleted();
    } catch (Exception ex) {
      ThrowUtil.onError(log, responseObserver, ex);
    }
  }

  @Override
  @RequiresAuthentication
  public void changePwd(ChangePwdReq request, StreamObserver<BoolValue> responseObserver) {
    try (UserWrite userWrite = RbacFactory.getUserWrite(request.getTenant())) {
      String oldPwd = request.getEncodeOldPwd();
      String newPwd = request.getEncodeNewPwd();
      boolean r = userWrite.changePwd(oldPwd, newPwd);
      responseObserver.onNext(BoolValue.of(r));
      responseObserver.onCompleted();
    } catch (Exception ex) {
      ThrowUtil.onError(log, responseObserver, ex);
    }
  }

  @Override
  @RequiresAuthentication
  public void changePhoneEmail(ChangePhoneEmailReq request,
      StreamObserver<BoolValue> responseObserver) {
    try (UserWrite userWrite = RbacFactory.getUserWrite(request.getTenant())) {
      boolean r = userWrite.changePhoneEmail(request);
      responseObserver.onNext(BoolValue.of(r));
      responseObserver.onCompleted();
    } catch (Exception ex) {
      ThrowUtil.onError(log, responseObserver, ex);
    }
  }

  @Override
  @RequiresAuthentication
  public void changeWechatBind(ChangeWechatBindReq request,
      StreamObserver<BoolValue> responseObserver) {
    try (UserWrite userWrite = RbacFactory.getUserWrite(request.getTenant())) {
      boolean r = userWrite.changeWechatBind(request);
      responseObserver.onNext(BoolValue.of(r));
      responseObserver.onCompleted();
    } catch (Exception ex) {
      ThrowUtil.onError(log, responseObserver, ex);
    }
  }

  @Override
  public void registerUser(RegisterUserReq request, StreamObserver<TokenResp> responseObserver) {
    try (UserWrite userWrite = RbacFactory.getUserWrite(request.getTenant())) {
      TokenEntity tokenEntity = userWrite.registerUser(request);
      responseObserver.onNext(RbacMapper.INSTANCE.model(tokenEntity));
      responseObserver.onCompleted();
    } catch (Exception ex) {
      ThrowUtil.onError(log, responseObserver, ex);
    }
  }

  @Override
  public void forgotPwd(ForgotPwdReq request, StreamObserver<BoolValue> responseObserver) {
    try (UserWrite userWrite = RbacFactory.getUserWrite(request.getTenant())) {
      boolean r = userWrite.forgotPwd(request);
      responseObserver.onNext(BoolValue.of(r));
      responseObserver.onCompleted();
    } catch (Exception ex) {
      ThrowUtil.onError(log, responseObserver, ex);
    }
  }

  @Override
  @RequiresAuthentication
  public void runAsUser(RunAsReq request, StreamObserver<UserModel> responseObserver) {
    try (UserRead userRead = RbacFactory.getUserRead(request.getTenant())) {
      UserEntity toUser = userRead.findById(UUIDUtil.fromString(request.getUserId()));
      if (null == toUser) {
        responseObserver.onError(Status.INTERNAL.withDescription("找不到切换身份用户！").asException());
        return;
      }
      RunAsUtil.runAs(request, toUser, event);
      UserModel resp = UserMapper.INSTANCE.model(toUser);
      resp = RunAsUtil.markRunAsInfo(resp);
      responseObserver.onNext(resp);
      responseObserver.onCompleted();
    } catch (Exception ex) {
      ThrowUtil.onError(log, responseObserver, ex);
    }
  }

  @Override
  @RequiresAuthentication
  public void allowRunAsUser(TenantReq request, StreamObserver<UserList> responseObserver) {
    try (UserRead userRead = RbacFactory.getUserRead(request.getTenant())) {
      List<UserEntity> users = userRead.findListByReq(
          UserReq.newBuilder().setRoleCode(RoleEntity.TESTER).setTenant("rbac").build());
      List<UserModel> resp = UserMapper.INSTANCE.listUser(users);
      resp = RunAsUtil.markRunAsInfo(resp);
      responseObserver.onNext(UserList.newBuilder().addAllResults(resp).build());
      responseObserver.onCompleted();
    } catch (Exception ex) {
      ThrowUtil.onError(log, responseObserver, ex);
    }
  }

  @Override
  @RequiresAuthentication
  public void findDeptList(DeptReq request, StreamObserver<DeptList> responseObserver) {
    try (DeptRead deptRead = RbacFactory.getDeptRead(request.getTenant())) {
      List<DeptEntity> list = deptRead.findListByReq(request);
      DeptList modelList = DeptMapper.INSTANCE.listTreeDept(list);
      responseObserver.onNext(modelList);
      responseObserver.onCompleted();
    } catch (Exception ex) {
      ThrowUtil.onError(log, responseObserver, ex);
    }
  }

  @Override
  public void findDeptTreeList(DeptReq request, StreamObserver<TreeList> responseObserver) {
    if ((!request.getHasOpen() || !request.getIsOpen()) && !PermUtils.isAuthenticated()) {
      responseObserver.onError(Status.PERMISSION_DENIED.withDescription("403没有访问权限").asException());
      return;
    }
    try (DeptRead deptRead = RbacFactory.getDeptRead(request.getTenant())) {
      List<TreeResult> list = deptRead.findTreeList(request);
      TreeList modelList = RbacMapper.INSTANCE.treeList(list, request.getExcludeId());
      responseObserver.onNext(modelList);
      responseObserver.onCompleted();
    } catch (Exception ex) {
      ThrowUtil.onError(log, responseObserver, ex);
    }
  }

  @Override
  @RequiresPermissions("rbac:dept:view")
  public void findDeptById(DeptKey request, StreamObserver<DeptModel> responseObserver) {
    try (DeptRead deptRead = RbacFactory.getDeptRead(request.getTenant())) {
      DeptEntity entity = deptRead.findById(UUIDUtil.fromString(request.getDeptId()));
      DeptModel model = DeptMapper.INSTANCE.model(entity);
      responseObserver.onNext(model);
      responseObserver.onCompleted();
    } catch (Exception ex) {
      ThrowUtil.onError(log, responseObserver, ex);
    }
  }

  @Override
  @RequiresPermissions("rbac:dept:add")
  public void createDept(DeptCreateReq request, StreamObserver<DeptModel> responseObserver) {
    try (DeptWrite deptWrite = RbacFactory.getDeptWrite(request.getTenant())) {
      DeptEntity entity = deptWrite.insert(request);
      DeptModel model = DeptMapper.INSTANCE.model(entity);
      responseObserver.onNext(model);
      responseObserver.onCompleted();
    } catch (Exception ex) {
      ThrowUtil.onError(log, responseObserver, ex);
    }
  }

  @Override
  @RequiresPermissions("rbac:dept:update")
  public void updateDept(DeptUpdateReq request, StreamObserver<DeptModel> responseObserver) {
    try (DeptWrite deptWrite = RbacFactory.getDeptWrite(request.getTenant())) {
      DeptEntity entity = deptWrite.update(request);
      DeptModel model = DeptMapper.INSTANCE.model(entity);
      responseObserver.onNext(model);
      responseObserver.onCompleted();
    } catch (Exception ex) {
      ThrowUtil.onError(log, responseObserver, ex);
    }
  }

  @Override
  @RequiresPermissions("rbac:dept:delete")
  public void deleteDept(DeptKey request, StreamObserver<DeptModel> responseObserver) {
    try (DeptWrite deptWrite = RbacFactory.getDeptWrite(request.getTenant())) {
      DeptEntity entity = deptWrite.delete(UUIDUtil.fromString(request.getDeptId()));
      DeptModel model = DeptMapper.INSTANCE.model(entity);
      responseObserver.onNext(model);
      responseObserver.onCompleted();
    } catch (Exception ex) {
      ThrowUtil.onError(log, responseObserver, ex);
    }
  }

  @Override
  @RequiresPermissions("rbac:dept:delete")
  public void batchDeleteDept(DeptKeyList request, StreamObserver<Int32Value> responseObserver) {
    try (DeptWrite deptWrite = RbacFactory.getDeptWrite(request.getTenant())) {
      final Set<UUID> set = request.getDeptIdList().stream().map(v -> UUIDUtil.fromString(v))
          .collect(Collectors.toSet());
      int r = deptWrite.batchDelete(set);
      responseObserver.onNext(Int32Value.of(r));
      responseObserver.onCompleted();
    } catch (Exception ex) {
      ThrowUtil.onError(log, responseObserver, ex);
    }
  }

  @Override
  @RequiresPermissions("rbac:dept:move")
  public void moveDept(DeptMoveKey request, StreamObserver<BoolValue> responseObserver) {
    try (DeptWrite deptWrite = RbacFactory.getDeptWrite(request.getTenant())) {
      boolean r = deptWrite.moveOrderBy(request);
      responseObserver.onNext(BoolValue.of(r));
      responseObserver.onCompleted();
    } catch (Exception ex) {
      ThrowUtil.onError(log, responseObserver, ex);
    }
  }

  @Override
  @RequiresAuthentication
  public void updateDeptCount(DeptCountUpdateReq request,
      StreamObserver<BoolValue> responseObserver) {
    try (DeptWrite deptWrite = RbacFactory.getDeptWrite(request.getTenant())) {
      boolean result = deptWrite.updateDeptCount(request);
      responseObserver.onNext(BoolValue.of(result));
      responseObserver.onCompleted();
    } catch (Exception ex) {
      ThrowUtil.onError(log, responseObserver, ex);
    }
  }

  @Override
  @RequiresPermissions("rbac:dept:lock")
  public void lockDept(EnableDeptReq request, StreamObserver<Int32Value> responseObserver) {
    try (DeptWrite deptWrite = RbacFactory.getDeptWrite(request.getTenant())) {
      final Set<UUID> set = request.getDeptIdList().stream().map(v -> UUIDUtil.fromString(v))
          .collect(Collectors.toSet());
      int r = deptWrite.lock(set, request.getEnable());
      responseObserver.onNext(Int32Value.of(r));
      responseObserver.onCompleted();
    } catch (Exception ex) {
      ThrowUtil.onError(log, responseObserver, ex);
    }
  }

  @Override
  @RequiresPermissions("rbac:dept:enable")
  public void enableDept(DeptEnableKey request, StreamObserver<BoolValue> responseObserver) {
    try (DeptWrite deptWrite = RbacFactory.getDeptWrite(request.getTenant())) {
      boolean r = deptWrite.enableDept(request);
      responseObserver.onNext(BoolValue.of(r));
      responseObserver.onCompleted();
    } catch (Exception ex) {
      ThrowUtil.onError(log, responseObserver, ex);
    }
  }

  @Override
  @RequiresPermissions("rbac:dept:download")
  public void downloadDept(TenantReq request, StreamObserver<HttpBody> responseObserver) {
    try (DeptRead deptRead = RbacFactory.getDeptRead(request.getTenant())) {
      String realFileSrc = deptRead.downloadDeptTemplate(request);
      FileServiceUtil.downloadFile(responseObserver, realFileSrc);
    } catch (Exception ex) {
      ThrowUtil.onError(log, responseObserver, ex);
    }
  }

  @Override
  @RequiresPermissions("rbac:dept:import")
  public void importDept(DeptImportReq request, StreamObserver<StringValue> responseObserver) {
    try (DeptWrite deptWrite = RbacFactory.getDeptWrite(request.getTenant())) {
      String r = deptWrite.importDept(request);
      responseObserver.onNext(StringValue.of(r));
      responseObserver.onCompleted();
    } catch (Exception ex) {
      ThrowUtil.onError(log, responseObserver, ex);
    }
  }

  @Override
  @RequiresPermissions("rbac:dept:export")
  public void exportDept(DeptExportReq request, StreamObserver<HttpBody> responseObserver) {
    try (DeptRead deptRead = RbacFactory.getDeptRead(request.getTenant())) {
      String realFileSrc = deptRead.exportDept(request);
      FileServiceUtil.downloadFile(responseObserver, realFileSrc);
    } catch (Exception ex) {
      ThrowUtil.onError(log, responseObserver, ex);
    }
  }

  @Override
  @RequiresPermissions("rbac:log:list")
  public void findLogPage(LogReq request, StreamObserver<LogPage> responseObserver) {
    try (LogRead logRead = RbacFactory.getLogRead(request.getTenant())) {
      DtoPage<LogEntity, DtoTotal> page = logRead.findPageByReq(request);
      LogPage modelPage = LogMapper.INSTANCE.pageLog(page);
      responseObserver.onNext(modelPage);
      responseObserver.onCompleted();
    } catch (Exception ex) {
      ThrowUtil.onError(log, responseObserver, ex);
    }
  }

  @Override
  @RequiresPermissions("rbac:log:list")
  public void findLogList(LogReq request, StreamObserver<LogList> responseObserver) {
    try (LogRead logRead = RbacFactory.getLogRead(request.getTenant())) {
      List<LogEntity> list = logRead.findListByReq(request);
      List<LogModel> modelList = LogMapper.INSTANCE.listLog(list);
      responseObserver.onNext(LogList.newBuilder().addAllResults(modelList).build());
      responseObserver.onCompleted();
    } catch (Exception ex) {
      ThrowUtil.onError(log, responseObserver, ex);
    }
  }

  @Override
  @RequiresPermissions("rbac:log:view")
  public void findLogById(LogKey request, StreamObserver<LogModel> responseObserver) {
    try (LogRead logRead = RbacFactory.getLogRead(request.getTenant())) {
      LogPk pk = LogMapper.INSTANCE.pk(request);
      LogEntity entity = logRead.findById(pk);
      LogModel model = LogMapper.INSTANCE.model(entity);
      responseObserver.onNext(model);
      responseObserver.onCompleted();
    } catch (Exception ex) {
      ThrowUtil.onError(log, responseObserver, ex);
    }
  }

  @Override
  @RequiresPermissions("rbac:log:delete")
  public void deleteLog(LogDelReq request, StreamObserver<Int32Value> responseObserver) {
    try (LogWrite logWrite = RbacFactory.getLogWrite(request.getTenant())) {
      int r = logWrite.batchDelete(request.getNumber());
      responseObserver.onNext(Int32Value.of(r));
      responseObserver.onCompleted();
    } catch (Exception ex) {
      ThrowUtil.onError(log, responseObserver, ex);
    }
  }

  @Override
  @RequiresPermissions("rbac:log:export")
  public void exportLog(LogExportReq request, StreamObserver<HttpBody> responseObserver) {
    try (LogRead logRead = RbacFactory.getLogRead(request.getTenant())) {
      String realFileSrc = logRead.exportLog(request);
      FileServiceUtil.downloadFile(responseObserver, realFileSrc);
    } catch (Exception ex) {
      ThrowUtil.onError(log, responseObserver, ex);
    }
  }

  @Override
  @RequiresPermissions("rbac:module:list")
  public void findModulePage(ModuleReq request, StreamObserver<ModulePage> responseObserver) {
    try (ModuleRead moduleRead = RbacFactory.getModuleRead(request.getTenant())) {
      DtoPage<ModuleEntity, DtoTotal> page = moduleRead.findPageByReq(request);
      ModulePage modelPage = ModuleMapper.INSTANCE.pageModule(page);
      responseObserver.onNext(modelPage);
      responseObserver.onCompleted();
    } catch (Exception ex) {
      ThrowUtil.onError(log, responseObserver, ex);
    }
  }

  @Override
  @RequiresAuthentication
  public void selectUserInfo(UserKey request, StreamObserver<UserDeptJobInfoRes> responseObserver) {
    try (UserRead userRead = RbacFactory.getUserRead(request.getTenant())) {
      UserDeptJobInfoRes userDeptInfo = userRead.getUserDeptInfo(request);
      responseObserver.onNext(userDeptInfo);
      responseObserver.onCompleted();
    } catch (Exception ex) {
      ThrowUtil.onError(log, responseObserver, ex);
    }
  }

  @Override
  @RequiresPermissions("rbac:module:list")
  public void findModuleList(ModuleReq request, StreamObserver<ModuleList> responseObserver) {
    try (ModuleRead moduleRead = RbacFactory.getModuleRead(request.getTenant())) {
      List<ModuleEntity> list = moduleRead.findListByReq(request);
      List<ModuleModel> modelList = ModuleMapper.INSTANCE.listModule(list);
      responseObserver.onNext(ModuleList.newBuilder().addAllResults(modelList).build());
      responseObserver.onCompleted();
    } catch (Exception ex) {
      ThrowUtil.onError(log, responseObserver, ex);
    }
  }

  @Override
  @RequiresPermissions("rbac:module:view")
  public void findModuleById(ModuleKey request, StreamObserver<ModuleModel> responseObserver) {
    try (ModuleRead moduleRead = RbacFactory.getModuleRead(request.getTenant())) {
      ModuleEntity entity = moduleRead.findById(UUIDUtil.fromString(request.getModuleId()));
      ModuleModel model = ModuleMapper.INSTANCE.model(entity);
      responseObserver.onNext(model);
      responseObserver.onCompleted();
    } catch (Exception ex) {
      ThrowUtil.onError(log, responseObserver, ex);
    }
  }

  @Override
  @RequiresPermissions("rbac:module:add")
  public void createModule(ModuleCreateReq request, StreamObserver<ModuleModel> responseObserver) {
    try (ModuleWrite moduleWrite = RbacFactory.getModuleWrite(request.getTenant())) {
      ModuleEntity entity = moduleWrite.insert(request);
      ModuleModel model = ModuleMapper.INSTANCE.model(entity);
      responseObserver.onNext(model);
      responseObserver.onCompleted();
    } catch (Exception ex) {
      ThrowUtil.onError(log, responseObserver, ex);
    }
  }

  @Override
  @RequiresPermissions("rbac:module:update")
  public void updateModule(ModuleUpdateReq request, StreamObserver<ModuleModel> responseObserver) {
    try (ModuleWrite moduleWrite = RbacFactory.getModuleWrite(request.getTenant())) {
      ModuleEntity entity = moduleWrite.update(request);
      ModuleModel model = ModuleMapper.INSTANCE.model(entity);
      responseObserver.onNext(model);
      responseObserver.onCompleted();
    } catch (Exception ex) {
      ThrowUtil.onError(log, responseObserver, ex);
    }
  }

  @Override
  @RequiresPermissions("rbac:module:delete")
  public void deleteModule(ModuleKey request, StreamObserver<ModuleModel> responseObserver) {
    try (ModuleWrite moduleWrite = RbacFactory.getModuleWrite(request.getTenant())) {
      ModuleEntity entity = moduleWrite.delete(UUIDUtil.fromString(request.getModuleId()));
      ModuleModel model = ModuleMapper.INSTANCE.model(entity);
      responseObserver.onNext(model);
      responseObserver.onCompleted();
    } catch (Exception ex) {
      ThrowUtil.onError(log, responseObserver, ex);
    }
  }

  @Override
  @RequiresPermissions("rbac:module:delete")
  public void batchDeleteModule(ModuleKeyList request,
      StreamObserver<Int32Value> responseObserver) {
    try (ModuleWrite moduleWrite = RbacFactory.getModuleWrite(request.getTenant())) {
      final Set<UUID> set = request.getModuleIdList().stream().map(v -> UUIDUtil.fromString(v))
          .collect(Collectors.toSet());

      int r = moduleWrite.batchDelete(set);
      responseObserver.onNext(Int32Value.of(r));
      responseObserver.onCompleted();
    } catch (Exception ex) {
      ThrowUtil.onError(log, responseObserver, ex);
    }
  }

  @Override
  @RequiresPermissions("rbac:module:move")
  public void moveModule(ModuleMoveKey request, StreamObserver<BoolValue> responseObserver) {
    try (ModuleWrite moduleWrite = RbacFactory.getModuleWrite(request.getTenant())) {
      boolean r = moduleWrite.moveOrderBy(request);
      responseObserver.onNext(BoolValue.of(r));
      responseObserver.onCompleted();
    } catch (Exception ex) {
      ThrowUtil.onError(log, responseObserver, ex);
    }
  }

  @Override
  @RequiresAuthentication
  public void checkModuleCode(ModuleCheck request, StreamObserver<BoolValue> responseObserver) {
    try (ModuleRead moduleRead = RbacFactory.getModuleRead(request.getTenant())) {
      boolean r = moduleRead.checkModuleCodeUnique(request.getModuleCode());
      responseObserver.onNext(BoolValue.of(r));
      responseObserver.onCompleted();
    } catch (Exception ex) {
      ThrowUtil.onError(log, responseObserver, ex);
    }
  }

  @Override
  @RequiresPermissions("rbac:opens:list")
  public void findOpensList(OpensReq request, StreamObserver<OpensList> responseObserver) {
    try (OpensRead opensRead = RbacFactory.getOpensRead(request.getTenant())) {
      List<OpensEntity> list = opensRead.findListByReq(request);
      List<OpensModel> modelList = OpensMapper.INSTANCE.listOpens(list);
      responseObserver.onNext(OpensList.newBuilder().addAllResults(modelList).build());
      responseObserver.onCompleted();
    } catch (Exception ex) {
      ThrowUtil.onError(log, responseObserver, ex);
    }
  }

  @Override
  @RequiresPermissions("rbac:opens:view")
  public void findOpensById(OpensKey request, StreamObserver<OpensModel> responseObserver) {
    try (OpensRead opensRead = RbacFactory.getOpensRead(request.getTenant())) {
      OpensPk pk = OpensMapper.INSTANCE.pk(request);
      OpensEntity entity = opensRead.findById(pk);
      OpensModel model = OpensMapper.INSTANCE.model(entity);
      responseObserver.onNext(model);
      responseObserver.onCompleted();
    } catch (Exception ex) {
      ThrowUtil.onError(log, responseObserver, ex);
    }
  }

  @Override
  @RequiresPermissions("rbac:opens:delete")
  public void deleteOpens(OpensKey request, StreamObserver<OpensModel> responseObserver) {
    try (UserWrite userWrite = RbacFactory.getUserWrite(request.getTenant())) {
      OpensPk pk = OpensMapper.INSTANCE.pk(request);
      OpensEntity entity = userWrite.deleteUserOpens(pk);
      OpensModel model = OpensMapper.INSTANCE.model(entity);
      responseObserver.onNext(model);
      responseObserver.onCompleted();
    } catch (Exception ex) {
      ThrowUtil.onError(log, responseObserver, ex);
    }
  }

  // 无需权限
  @Override
  public void findOpensUnionId(UserOpensReq request, StreamObserver<UnionIdList> responseObserver) {
    try (OpensRead opensRead = RbacFactory.getOpensRead(request.getTenant())) {
      List<String> unionIds = opensRead.findOpensUnionId(request);
      responseObserver.onNext(UnionIdList.newBuilder().addAllUnionIds(unionIds).build());
      responseObserver.onCompleted();
    } catch (Exception ex) {
      ThrowUtil.onError(log, responseObserver, ex);
    }
  }

  // 无需权限
  @Override
  public void findMyOpensUnionId(TenantReq request, StreamObserver<UnionIdList> responseObserver) {
    try (OpensRead opensRead = RbacFactory.getOpensRead(request.getTenant())) {
      UUID userId = GrpcContext.getPrincipal().getNameUUID();
      List<String> unionIds = opensRead.findOpensUnionId(userId);
      responseObserver.onNext(UnionIdList.newBuilder().addAllUnionIds(unionIds).build());
      responseObserver.onCompleted();
    } catch (Exception ex) {
      ThrowUtil.onError(log, responseObserver, ex);
    }
  }

  @Override
  @RequiresPermissions("rbac:open_app:list")
  public void findOpenAppPage(OpenAppReq request, StreamObserver<OpenAppPage> responseObserver) {
    try (OpenAppRead openAppRead = RbacFactory.getOpenAppRead(request.getTenant())) {
      DtoPage<OpenAppEntity, DtoTotal> page = openAppRead.findPageByReq(request);
      OpenAppPage modelPage = OpenAppMapper.INSTANCE.pageOpenApp(page);
      responseObserver.onNext(modelPage);
      responseObserver.onCompleted();
    } catch (Exception ex) {
      ThrowUtil.onError(log, responseObserver, ex);
    }
  }

  @Override
  @RequiresPermissions("rbac:open_app:list")
  public void findOpenAppList(OpenAppReq request, StreamObserver<OpenAppList> responseObserver) {
    try (OpenAppRead openAppRead = RbacFactory.getOpenAppRead(request.getTenant())) {
      List<OpenAppEntity> list = openAppRead.findListByReq(request);
      List<OpenAppModel> modelList = OpenAppMapper.INSTANCE.listOpenApp(list);
      responseObserver.onNext(OpenAppList.newBuilder().addAllResults(modelList).build());
      responseObserver.onCompleted();
    } catch (Exception ex) {
      ThrowUtil.onError(log, responseObserver, ex);
    }
  }

  @Override
  @RequiresPermissions("rbac:open_app:view")
  public void findOpenAppById(OpenAppKey request, StreamObserver<OpenAppModel> responseObserver) {
    try (OpenAppRead openAppRead = RbacFactory.getOpenAppRead(request.getTenant())) {
      OpenAppEntity entity = openAppRead.findById(UUIDUtil.fromString(request.getOpenAppId()));
      OpenAppModel model = OpenAppMapper.INSTANCE.model(entity);
      responseObserver.onNext(model);
      responseObserver.onCompleted();
    } catch (Exception ex) {
      ThrowUtil.onError(log, responseObserver, ex);
    }
  }

  @Override
  @RequiresPermissions("rbac:open_app:add")
  public void createOpenApp(OpenAppCreateReq request,
      StreamObserver<OpenAppModel> responseObserver) {
    try (OpenAppWrite openAppWrite = RbacFactory.getOpenAppWrite(request.getTenant())) {
      OpenAppEntity entity = openAppWrite.insert(request);
      OpenAppModel model = OpenAppMapper.INSTANCE.model(entity);
      responseObserver.onNext(model);
      responseObserver.onCompleted();
    } catch (Exception ex) {
      ThrowUtil.onError(log, responseObserver, ex);
    }
  }

  @Override
  @RequiresPermissions("rbac:open_app:update")
  public void updateOpenApp(OpenAppUpdateReq request,
      StreamObserver<OpenAppModel> responseObserver) {
    try (OpenAppWrite openAppWrite = RbacFactory.getOpenAppWrite(request.getTenant())) {
      OpenAppEntity entity = openAppWrite.update(request);
      OpenAppModel model = OpenAppMapper.INSTANCE.model(entity);
      responseObserver.onNext(model);
      responseObserver.onCompleted();
    } catch (Exception ex) {
      ThrowUtil.onError(log, responseObserver, ex);
    }
  }

  @Override
  @RequiresPermissions("rbac:open_app:delete")
  public void deleteOpenApp(OpenAppKey request, StreamObserver<OpenAppModel> responseObserver) {
    try (OpenAppWrite openAppWrite = RbacFactory.getOpenAppWrite(request.getTenant())) {
      OpenAppEntity entity = openAppWrite.delete(UUIDUtil.fromString(request.getOpenAppId()));
      OpenAppModel model = OpenAppMapper.INSTANCE.model(entity);
      responseObserver.onNext(model);
      responseObserver.onCompleted();
    } catch (Exception ex) {
      ThrowUtil.onError(log, responseObserver, ex);
    }
  }

  @Override
  @RequiresPermissions("rbac:open_app:delete")
  public void batchDeleteOpenApp(OpenAppKeyList request,
      StreamObserver<Int32Value> responseObserver) {
    try (OpenAppWrite openAppWrite = RbacFactory.getOpenAppWrite(request.getTenant())) {
      final List<String> list = request.getOpenAppIdList();
      final Set<UUID> set =
          list.stream().map(v -> UUIDUtil.fromString(v)).collect(Collectors.toSet());

      int r = openAppWrite.batchDelete(set);
      responseObserver.onNext(Int32Value.of(r));
      responseObserver.onCompleted();
    } catch (Exception ex) {
      ThrowUtil.onError(log, responseObserver, ex);
    }
  }

  @Override
  @RequiresPermissions("rbac:operation:list")
  public void findOperationPage(OperationReq request,
      StreamObserver<OperationPage> responseObserver) {
    try (OperationRead operationRead = RbacFactory.getOperationRead(request.getTenant())) {
      DtoPage<OperationEntity, DtoTotal> page = operationRead.findPageByReq(request);
      OperationPage modelPage = OperationMapper.INSTANCE.pageOperation(page);
      responseObserver.onNext(modelPage);
      responseObserver.onCompleted();
    } catch (Exception ex) {
      ThrowUtil.onError(log, responseObserver, ex);
    }
  }

  @Override
  @RequiresPermissions("rbac:operation:list")
  public void findOperationList(OperationReq request,
      StreamObserver<OperationList> responseObserver) {
    try (OperationRead operationRead = RbacFactory.getOperationRead(request.getTenant())) {
      List<OperationEntity> list = operationRead.findListByReq(request);
      List<OperationModel> modelList = OperationMapper.INSTANCE.listOperation(list);
      responseObserver.onNext(OperationList.newBuilder().addAllResults(modelList).build());
      responseObserver.onCompleted();
    } catch (Exception ex) {
      ThrowUtil.onError(log, responseObserver, ex);
    }
  }

  @Override
  @RequiresPermissions("rbac:operation:view")
  public void findOperationById(OperationKey request,
      StreamObserver<OperationModel> responseObserver) {
    try (OperationRead operationRead = RbacFactory.getOperationRead(request.getTenant())) {
      OperationEntity entity =
          operationRead.findById(UUIDUtil.fromString(request.getOperationId()));
      OperationModel model = OperationMapper.INSTANCE.model(entity);
      responseObserver.onNext(model);
      responseObserver.onCompleted();
    } catch (Exception ex) {
      ThrowUtil.onError(log, responseObserver, ex);
    }
  }

  @Override
  @RequiresPermissions("rbac:operation:add")
  public void createOperation(OperationCreateReq request,
      StreamObserver<OperationModel> responseObserver) {
    try (OperationWrite operationWrite = RbacFactory.getOperationWrite(request.getTenant())) {
      OperationEntity entity = operationWrite.insert(request);
      OperationModel model = OperationMapper.INSTANCE.model(entity);
      responseObserver.onNext(model);
      responseObserver.onCompleted();
    } catch (Exception ex) {
      ThrowUtil.onError(log, responseObserver, ex);
    }
  }

  @Override
  @RequiresPermissions("rbac:operation:update")
  public void updateOperation(OperationUpdateReq request,
      StreamObserver<OperationModel> responseObserver) {
    try (OperationWrite operationWrite = RbacFactory.getOperationWrite(request.getTenant())) {
      OperationEntity entity = operationWrite.update(request);
      OperationModel model = OperationMapper.INSTANCE.model(entity);
      responseObserver.onNext(model);
      responseObserver.onCompleted();
    } catch (Exception ex) {
      ThrowUtil.onError(log, responseObserver, ex);
    }
  }

  @Override
  @RequiresPermissions("rbac:operation:delete")
  public void deleteOperation(OperationKey request,
      StreamObserver<OperationModel> responseObserver) {
    try (OperationWrite operationWrite = RbacFactory.getOperationWrite(request.getTenant())) {
      OperationEntity entity = operationWrite.delete(UUIDUtil.fromString(request.getOperationId()));
      OperationModel model = OperationMapper.INSTANCE.model(entity);
      responseObserver.onNext(model);
      responseObserver.onCompleted();
    } catch (Exception ex) {
      ThrowUtil.onError(log, responseObserver, ex);
    }
  }

  @Override
  @RequiresPermissions("rbac:operation:delete")
  public void batchDeleteOperation(OperationKeyList request,
      StreamObserver<Int32Value> responseObserver) {
    try (OperationWrite operationWrite = RbacFactory.getOperationWrite(request.getTenant())) {
      final Set<UUID> set = request.getOperationIdList().stream().map(v -> UUIDUtil.fromString(v))
          .collect(Collectors.toSet());

      int r = operationWrite.batchDelete(set);
      responseObserver.onNext(Int32Value.of(r));
      responseObserver.onCompleted();
    } catch (Exception ex) {
      ThrowUtil.onError(log, responseObserver, ex);
    }
  }

  @Override
  @RequiresPermissions("rbac:operation:move")
  public void moveOperation(OperationMoveKey request, StreamObserver<BoolValue> responseObserver) {
    try (OperationWrite operationWrite = RbacFactory.getOperationWrite(request.getTenant())) {
      boolean r = operationWrite.moveOrderBy(request);
      responseObserver.onNext(BoolValue.of(r));
      responseObserver.onCompleted();
    } catch (Exception ex) {
      ThrowUtil.onError(log, responseObserver, ex);
    }
  }

  @Override
  @RequiresAuthentication
  public void checkOperationCode(OperationCheck request,
      StreamObserver<BoolValue> responseObserver) {
    try (OperationRead operationRead = RbacFactory.getOperationRead(request.getTenant())) {
      boolean r = operationRead.checkOperationCodeUnique(request.getOperationCode());
      responseObserver.onNext(BoolValue.of(r));
      responseObserver.onCompleted();
    } catch (Exception ex) {
      ThrowUtil.onError(log, responseObserver, ex);
    }
  }

  @Override
  @RequiresPermissions("rbac:perm:list")
  public void findPermPage(PermReq request, StreamObserver<PermPage> responseObserver) {
    try (PermRead permRead = RbacFactory.getPermRead(request.getTenant())) {
      DtoPage<PermEntity, DtoTotal> page = permRead.findPageByReq(request);
      PermPage modelPage = PermMapper.INSTANCE.pagePerm(page);
      responseObserver.onNext(modelPage);
      responseObserver.onCompleted();
    } catch (Exception ex) {
      ThrowUtil.onError(log, responseObserver, ex);
    }
  }

  @Override
  @RequiresPermissions("rbac:perm:list")
  public void findPermList(PermReq request, StreamObserver<PermList> responseObserver) {
    try (PermRead permRead = RbacFactory.getPermRead(request.getTenant())) {
      List<PermEntity> list = permRead.findListByReq(request);
      List<PermModel> modelList = PermMapper.INSTANCE.listPerm(list);
      responseObserver.onNext(PermList.newBuilder().addAllResults(modelList).build());
      responseObserver.onCompleted();
    } catch (Exception ex) {
      ThrowUtil.onError(log, responseObserver, ex);
    }
  }

  @Override
  @RequiresAuthentication
  public void checkPermCode(PermCheck request, StreamObserver<BoolValue> responseObserver) {
    try (PermRead permRead = RbacFactory.getPermRead(request.getTenant())) {
      boolean r = permRead.checkPermCodeUnique(request.getPermCode());
      responseObserver.onNext(BoolValue.of(r));
      responseObserver.onCompleted();
    } catch (Exception ex) {
      ThrowUtil.onError(log, responseObserver, ex);
    }
  }

  @Override
  @RequiresPermissions("rbac:perm:view")
  public void findPermById(PermKey request, StreamObserver<PermModel> responseObserver) {
    try (PermRead permRead = RbacFactory.getPermRead(request.getTenant())) {
      PermEntity entity = permRead.findById(UUIDUtil.fromString(request.getPermId()));
      PermModel model = PermMapper.INSTANCE.model(entity);
      responseObserver.onNext(model);
      responseObserver.onCompleted();
    } catch (Exception ex) {
      ThrowUtil.onError(log, responseObserver, ex);
    }
  }

  @Override
  @RequiresPermissions("rbac:perm:add")
  public void createPerm(PermCreateReq request, StreamObserver<PermModel> responseObserver) {
    try (PermWrite permWrite = RbacFactory.getPermWrite(request.getTenant())) {
      PermEntity entity = permWrite.insert(request);
      PermModel model = PermMapper.INSTANCE.model(entity);
      responseObserver.onNext(model);
      responseObserver.onCompleted();
    } catch (Exception ex) {
      ThrowUtil.onError(log, responseObserver, ex);
    }
  }

  @Override
  @RequiresPermissions("rbac:perm:update")
  public void updatePerm(PermUpdateReq request, StreamObserver<PermModel> responseObserver) {
    try (PermWrite permWrite = RbacFactory.getPermWrite(request.getTenant())) {
      PermEntity entity = permWrite.update(request);
      PermModel model = PermMapper.INSTANCE.model(entity);
      responseObserver.onNext(model);
      responseObserver.onCompleted();
    } catch (Exception ex) {
      ThrowUtil.onError(log, responseObserver, ex);
    }
  }

  @Override
  @RequiresPermissions("rbac:perm:delete")
  public void deletePerm(PermKey request, StreamObserver<PermModel> responseObserver) {
    try (PermWrite permWrite = RbacFactory.getPermWrite(request.getTenant())) {
      PermEntity entity = permWrite.delete(UUIDUtil.fromString(request.getPermId()));
      PermModel model = PermMapper.INSTANCE.model(entity);
      responseObserver.onNext(model);
      responseObserver.onCompleted();
    } catch (Exception ex) {
      ThrowUtil.onError(log, responseObserver, ex);
    }
  }

  @Override
  @RequiresPermissions("rbac:perm:delete")
  public void batchDeletePerm(PermKeyList request, StreamObserver<Int32Value> responseObserver) {
    try (PermWrite permWrite = RbacFactory.getPermWrite(request.getTenant())) {
      final Set<UUID> set = request.getPermIdList().stream().map(v -> UUIDUtil.fromString(v))
          .collect(Collectors.toSet());
      int r = permWrite.batchDelete(set);
      responseObserver.onNext(Int32Value.of(r));
      responseObserver.onCompleted();
    } catch (Exception ex) {
      ThrowUtil.onError(log, responseObserver, ex);
    }
  }

  @Override
  @RequiresPermissions("rbac:resource:list")
  public void findResourceList(ResourceReq request, StreamObserver<ResourceList> responseObserver) {
    try (ResourceRead resourceRead = RbacFactory.getResourceRead(request.getTenant())) {
      List<ResourceEntity> list = resourceRead.findListByReq(request);
      ResourceList modelList = ResourceMapper.INSTANCE.listResource(list);
      responseObserver.onNext(modelList);
      responseObserver.onCompleted();
    } catch (Exception ex) {
      ThrowUtil.onError(log, responseObserver, ex);
    }
  }

  @Override
  @RequiresAuthentication
  public void findResourceTreeList(ResourceReq request, StreamObserver<TreeList> responseObserver) {
    try (ResourceRead resouceRead = RbacFactory.getResourceRead(request.getTenant())) {
      List<TreeResult> list = resouceRead.findTreeList();
      TreeList modelList = RbacMapper.INSTANCE.treeList(list, request.getExcludeId());
      responseObserver.onNext(modelList);
      responseObserver.onCompleted();
    } catch (Exception ex) {
      ThrowUtil.onError(log, responseObserver, ex);
    }
  }

  @Override
  @RequiresPermissions("rbac:resource:view")
  public void findResourceById(ResourceKey request,
      StreamObserver<ResourceModel> responseObserver) {
    try (ResourceRead resouceRead = RbacFactory.getResourceRead(request.getTenant())) {
      ResourceEntity entity = resouceRead.findById(UUIDUtil.fromString(request.getResourceId()));
      List<String> perms = resouceRead.findResourcePerm(entity);
      ResourceModel model = ResourceMapper.INSTANCE.modelPerms(entity, perms);
      responseObserver.onNext(model);
      responseObserver.onCompleted();
    } catch (Exception ex) {
      ThrowUtil.onError(log, responseObserver, ex);
    }
  }

  @Override
  @RequiresPermissions("rbac:resource:add")
  public void createResource(ResourceCreateReq request,
      StreamObserver<ResourceModel> responseObserver) {
    try (ResourceWrite resourceWrite = RbacFactory.getResourceWrite(request.getTenant())) {
      ResourceEntity entity = resourceWrite.insert(request);
      ResourceModel model = ResourceMapper.INSTANCE.model(entity);
      responseObserver.onNext(model);
      responseObserver.onCompleted();
    } catch (Exception ex) {
      ThrowUtil.onError(log, responseObserver, ex);
    }
  }

  @Override
  @RequiresPermissions("rbac:resource:update")
  public void updateResource(ResourceUpdateReq request,
      StreamObserver<ResourceModel> responseObserver) {
    try (ResourceWrite resourceWrite = RbacFactory.getResourceWrite(request.getTenant())) {
      ResourceEntity entity = resourceWrite.update(request);
      ResourceModel model = ResourceMapper.INSTANCE.model(entity);
      responseObserver.onNext(model);
      responseObserver.onCompleted();
    } catch (Exception ex) {
      ThrowUtil.onError(log, responseObserver, ex);
    }
  }

  @Override
  @RequiresPermissions("rbac:resource:delete")
  public void deleteResource(ResourceKey request, StreamObserver<ResourceModel> responseObserver) {
    try (ResourceWrite resourceWrite = RbacFactory.getResourceWrite(request.getTenant())) {
      ResourceEntity entity = resourceWrite.delete(UUIDUtil.fromString(request.getResourceId()));
      ResourceModel model = ResourceMapper.INSTANCE.model(entity);
      responseObserver.onNext(model);
      responseObserver.onCompleted();
    } catch (Exception ex) {
      ThrowUtil.onError(log, responseObserver, ex);
    }
  }

  @Override
  @RequiresPermissions("rbac:resource:delete")
  public void batchDeleteResource(ResourceKeyList request,
      StreamObserver<Int32Value> responseObserver) {
    try (ResourceWrite resourceWrite = RbacFactory.getResourceWrite(request.getTenant())) {
      final Set<UUID> set = request.getResourceIdList().stream().map(v -> UUIDUtil.fromString(v))
          .collect(Collectors.toSet());
      int r = resourceWrite.batchDelete(set);
      responseObserver.onNext(Int32Value.of(r));
      responseObserver.onCompleted();
    } catch (Exception ex) {
      ThrowUtil.onError(log, responseObserver, ex);
    }
  }

  @Override
  @RequiresPermissions("rbac:resource:export")
  public void exportResource(ResourceExportReq request, StreamObserver<HttpBody> responseObserver) {
    try (ResourceRead resourceRead = RbacFactory.getResourceRead(request.getTenant())) {
      String realFileSrc = resourceRead.exportResource(request);
      FileServiceUtil.downloadFile(responseObserver, realFileSrc);
    } catch (Exception ex) {
      ThrowUtil.onError(log, responseObserver, ex);
    }
  }

  @Override
  @RequiresPermissions("rbac:resource:download")
  public void downloadResource(ResourceExportReq request,
      StreamObserver<HttpBody> responseObserver) {
    try (ResourceRead resourceRead = RbacFactory.getResourceRead(request.getTenant())) {
      String realFileSrc = resourceRead.downloadResourceTemplate(request);
      FileServiceUtil.downloadFile(responseObserver, realFileSrc);
    } catch (Exception ex) {
      ThrowUtil.onError(log, responseObserver, ex);
    }
  }

  @Override
  @RequiresPermissions("rbac:resource:import")
  public void importResource(ResourceImportReq request,
      StreamObserver<StringValue> responseObserver) {
    try (ResourceWrite resourceWrite = RbacFactory.getResourceWrite(request.getTenant())) {
      String r = resourceWrite.importResource(request);
      responseObserver.onNext(StringValue.of(r));
      responseObserver.onCompleted();
    } catch (Exception ex) {
      ThrowUtil.onError(log, responseObserver, ex);
    }
  }

  @Override
  @RequiresAuthentication
  public void existResource(VerifyResourceReq request, StreamObserver<BoolValue> responseObserver) {
    try (ResourceRead resourceRead = RbacFactory.getResourceRead(request.getTenant())) {
      boolean result = resourceRead.checkResourceUrl(request.getUrl());
      responseObserver.onNext(BoolValue.of(result));
      responseObserver.onCompleted();
    } catch (Exception ex) {
      ThrowUtil.onError(log, responseObserver, ex);
    }
  }

  @Override
  @RequiresPermissions("rbac:resource:move")
  public void moveResouce(ResourceMoveKey request, StreamObserver<BoolValue> responseObserver) {
    try (ResourceWrite resourceWrite = RbacFactory.getResourceWrite(request.getTenant())) {
      boolean result = resourceWrite.moveOrderBy(request);
      responseObserver.onNext(BoolValue.of(result));
      responseObserver.onCompleted();
    } catch (Exception ex) {
      ThrowUtil.onError(log, responseObserver, ex);
    }
  }

  @Override
  @RequiresAuthentication
  public void findResourcePermList(ResourceReq request,
      StreamObserver<ResourcePermList> responseObserver) {
    try (ResourceRead resourceRead = RbacFactory.getResourceRead(request.getTenant())) {
      List<ResourcePermResult> resourcePermResults = resourceRead.findListByResource(request);
      // 获取资源对应的权限
      ResourcePermList modelList = PermMapper.INSTANCE.listResourcePerm(resourcePermResults);
      responseObserver.onNext(modelList);
      responseObserver.onCompleted();
    } catch (Exception ex) {
      ThrowUtil.onError(log, responseObserver, ex);
    }
  }

  @Override
  @RequiresPermissions(value = {"rbac:role:list", "rbac:job:list"}, logical = Logical.OR)
  public void findRoleList(RoleReq request, StreamObserver<RoleList> responseObserver) {
    try (RoleRead roleRead = RbacFactory.getRoleRead(request.getTenant())) {
      List<RoleEntity> list = roleRead.findListByReq(request);
      RoleList roleList = RoleMapper.INSTANCE.listRole(list);
      responseObserver.onNext(roleList);
      responseObserver.onCompleted();
    } catch (Exception ex) {
      ThrowUtil.onError(log, responseObserver, ex);
    }
  }

  @Override
  @RequiresPermissions(value = {"rbac:role:list", "rbac:job:list"}, logical = Logical.OR)
  public void findRoleDetailList(RoleDetailReq request, StreamObserver<RoleList> responseObserver) {
    try (RoleRead roleRead = RbacFactory.getRoleRead(request.getTenant());
        PermRead permRead = RbacFactory.getPermRead(request.getTenant())) {
      RoleReq req = RoleReq.newBuilder().setTenant(request.getTenant())
          .setLikeRoleName(request.getLikeRoleName()).setHasRoleType(request.getHasRoleType())
          .setRoleType(request.getRoleType()).build();
      List<RoleEntity> list = roleRead.findListByReq(req);
      List<RoleModel> modelList = new ArrayList<>();
      for (RoleEntity entity : list) {
        PermReq permReq = PermReq.newBuilder().setTenant(req.getTenant())
            .setLikePermCode(request.getLikePermCode()).setRoleId(entity.getRoleId().toString())
            .build();
        List<PermEntity> permList = permRead.findListByReq(permReq);
        List<String> permCodes =
            permList.stream().map(permEntity -> permEntity.getPermCode()).toList();
        RoleModel model = RoleMapper.INSTANCE.model(entity, permCodes, null);
        modelList.add(model);
      }
      RoleList roleList = RoleMapper.INSTANCE.listDetailRole(modelList);
      responseObserver.onNext(roleList);
      responseObserver.onCompleted();
    } catch (Exception ex) {
      ThrowUtil.onError(log, responseObserver, ex);
    }
  }

  @Override
  @RequiresAuthentication
  public void findRoleTreeList(RoleReq request, StreamObserver<TreeList> responseObserver) {
    try (RoleRead roleRead = RbacFactory.getRoleRead(request.getTenant())) {
      List<TreeResult> list = roleRead.findTreeList(request);
      TreeList roleList = RbacMapper.INSTANCE.treeList(list, request.getExcludeId());
      responseObserver.onNext(roleList);
      responseObserver.onCompleted();
    } catch (Exception ex) {
      ThrowUtil.onError(log, responseObserver, ex);
    }
  }

  @Override
  @RequiresPermissions(value = {"rbac:role:view", "rbac:job:view"}, logical = Logical.OR)
  public void findRoleById(RoleKey request, StreamObserver<RoleModel> responseObserver) {
    try (RoleRead roleRead = RbacFactory.getRoleRead(request.getTenant())) {
      try (PermRead permRead = RbacFactory.getPermRead(request.getTenant())) {
        RoleEntity entity = roleRead.findById(UUIDUtil.fromString(request.getRoleId()));
        List<String> permCodes = permRead.findRolePerms(entity.getRoleId());
        List<RolesDutyEntity> dutyList = roleRead.findDutyList(entity.getRoleId());
        RoleModel model = RoleMapper.INSTANCE.model(entity, permCodes, dutyList);
        responseObserver.onNext(model);
        responseObserver.onCompleted();
      }
    } catch (Exception ex) {
      ThrowUtil.onError(log, responseObserver, ex);
    }
  }

  @Override
  @RequiresPermissions(value = {"rbac:role:add", "rbac:job:add"}, logical = Logical.OR)
  public void createRole(RoleCreateReq request, StreamObserver<RoleModel> responseObserver) {
    try (RoleWrite roleWrite = RbacFactory.getRoleWrite(request.getTenant())) {
      RoleEntity entity = roleWrite.insert(request);
      RoleModel model = RoleMapper.INSTANCE.model(entity);
      responseObserver.onNext(model);
      responseObserver.onCompleted();
    } catch (Exception ex) {
      ThrowUtil.onError(log, responseObserver, ex);
    }
  }

  @Override
  @RequiresPermissions(value = {"rbac:role:update", "rbac:job:update"}, logical = Logical.OR)
  public void updateRole(RoleUpdateReq request, StreamObserver<RoleModel> responseObserver) {
    try (RoleWrite roleWrite = RbacFactory.getRoleWrite(request.getTenant())) {
      RoleEntity entity = roleWrite.update(request);
      RoleModel model = RoleMapper.INSTANCE.model(entity);
      responseObserver.onNext(model);
      responseObserver.onCompleted();
    } catch (Exception ex) {
      ThrowUtil.onError(log, responseObserver, ex);
    }
  }

  @Override
  @RequiresPermissions(value = {"rbac:role:delete", "rbac:job:delete"}, logical = Logical.OR)
  public void deleteRole(RoleKey request, StreamObserver<RoleModel> responseObserver) {
    try (RoleWrite roleWrite = RbacFactory.getRoleWrite(request.getTenant())) {
      RoleEntity entity = roleWrite.delete(UUIDUtil.fromString(request.getRoleId()));
      RoleModel model = RoleMapper.INSTANCE.model(entity);
      responseObserver.onNext(model);
      responseObserver.onCompleted();
    } catch (Exception ex) {
      ThrowUtil.onError(log, responseObserver, ex);
    }
  }

  @Override
  @RequiresPermissions(value = {"rbac:role:delete", "rbac:job:delete"}, logical = Logical.OR)
  public void batchDeleteRole(RoleKeyList request, StreamObserver<Int32Value> responseObserver) {
    try (RoleWrite roleWrite = RbacFactory.getRoleWrite(request.getTenant())) {
      final Set<UUID> set = request.getRoleIdList().stream().map(v -> UUIDUtil.fromString(v))
          .collect(Collectors.toSet());
      int r = roleWrite.batchDelete(set);
      responseObserver.onNext(Int32Value.of(r));
      responseObserver.onCompleted();
    } catch (Exception ex) {
      ThrowUtil.onError(log, responseObserver, ex);
    }
  }

  @Override
  @RequiresPermissions(value = {"rbac:role:move", "rbac:job:move"}, logical = Logical.OR)
  public void moveRole(RoleMoveKey request, StreamObserver<BoolValue> responseObserver) {
    try (RoleWrite roleWrite = RbacFactory.getRoleWrite(request.getTenant())) {
      boolean r = roleWrite.moveOrderBy(request);
      responseObserver.onNext(BoolValue.of(r));
      responseObserver.onCompleted();
    } catch (Exception ex) {
      ThrowUtil.onError(log, responseObserver, ex);
    }
  }

  @Override
  @RequiresPermissions("rbac:role:update")
  public void grantPerm(RolePermReq request, StreamObserver<Int32Value> responseObserver) {
    try (PermWrite permWrite = RbacFactory.getPermWrite(request.getTenant())) {
      UUID roleId = UUIDUtil.fromString(request.getRoleId());
      Set<String> permCodes = request.getPermCodesList().stream().collect(Collectors.toSet());
      Integer count = permWrite.grantPerm(roleId, permCodes);
      responseObserver.onNext(Int32Value.of(count));
      responseObserver.onCompleted();
    } catch (Exception ex) {
      ThrowUtil.onError(log, responseObserver, ex);
    }
  }

  @Override
  @RequiresPermissions("rbac:role:update")
  public void revokePerm(RolePermReq request, StreamObserver<Int32Value> responseObserver) {
    try (PermWrite permWrite = RbacFactory.getPermWrite(request.getTenant())) {
      UUID roleId = UUIDUtil.fromString(request.getRoleId());
      Set<String> permCodes = request.getPermCodesList().stream().collect(Collectors.toSet());
      Integer count = permWrite.revokePerm(roleId, permCodes);
      responseObserver.onNext(Int32Value.of(count));
      responseObserver.onCompleted();
    } catch (Exception ex) {
      ThrowUtil.onError(log, responseObserver, ex);
    }
  }

  @Override
  @RequiresAuthentication
  public void existRole(VerifyRoleReq request, StreamObserver<BoolValue> responseObserver) {
    try (RoleRead roleRead = RbacFactory.getRoleRead(request.getTenant())) {
      boolean result = roleRead.checkRoleCode(request);
      responseObserver.onNext(BoolValue.of(result));
      responseObserver.onCompleted();
    } catch (Exception ex) {
      ThrowUtil.onError(log, responseObserver, ex);
    }
  }

  @Override
  @RequiresAuthentication
  public void findUserPage(UserReq request, StreamObserver<UserPage> responseObserver) {
    try (UserRead userRead = RbacFactory.getUserRead(request.getTenant())) {
      DtoPage<UserEntity, DtoTotal> page = userRead.findPageByReq(request);
      UserPage modelPage = UserMapper.INSTANCE.pageUser(page);
      responseObserver.onNext(modelPage);
      responseObserver.onCompleted();
    } catch (Exception ex) {
      ThrowUtil.onError(log, responseObserver, ex);
    }
  }

  @Override
  @RequiresPermissions("rbac:user:list")
  public void findUserList(UserReq request, StreamObserver<UserList> responseObserver) {
    try (UserRead userRead = RbacFactory.getUserRead(request.getTenant())) {
      List<UserEntity> list = userRead.findListByReq(request);
      List<UserModel> modelList = UserMapper.INSTANCE.listUser(list);
      responseObserver.onNext(UserList.newBuilder().addAllResults(modelList).build());
      responseObserver.onCompleted();
    } catch (Exception ex) {
      ThrowUtil.onError(log, responseObserver, ex);
    }
  }

  @Override
  @RequiresPermissions("rbac:user:view")
  public void findUserById(UserKey request, StreamObserver<UserModel> responseObserver) {
    try (UserRead userRead = RbacFactory.getUserRead(request.getTenant())) {
      UserModel model = userRead.findUserById(UUIDUtil.fromString(request.getUserId()));
      responseObserver.onNext(model);
      responseObserver.onCompleted();
    } catch (Exception ex) {
      ThrowUtil.onError(log, responseObserver, ex);
    }
  }

  @Override
  @RequiresAuthentication
  public void findUserByName(UserNameReq request, StreamObserver<UserModel> responseObserver) {
    try (UserRead userRead = RbacFactory.getUserRead(request.getTenant())) {
      UserEntity entity = userRead.findByUserName(request.getDirectoryId(), request.getUserName());
      UserModel model = UserMapper.INSTANCE.model(entity);
      responseObserver.onNext(model);
      responseObserver.onCompleted();
    } catch (Exception ex) {
      ThrowUtil.onError(log, responseObserver, ex);
    }
  }

  @Override
  @RequiresAuthentication
  public void findUserInfoList(UserReq request, StreamObserver<UserInfoList> responseObserver) {
    try (UserRead userRead = RbacFactory.getUserRead(request.getTenant())) {
      request =
          request.toBuilder().setHasUserStatus(true).setUserStatus(UserStatus.enabled).build();
      List<UserInfo> modelList = userRead.findUserListByReq(request);
      responseObserver.onNext(UserInfoList.newBuilder().addAllResults(modelList).build());
      responseObserver.onCompleted();
    } catch (Exception ex) {
      ThrowUtil.onError(log, responseObserver, ex);
    }
  }

  @Override
  @RequiresAuthentication
  public void findUserInfoPage(UserReq request, StreamObserver<UserInfoPage> responseObserver) {
    try (UserRead userRead = RbacFactory.getUserRead(request.getTenant())) {
      request =
          request.toBuilder().setHasUserStatus(true).setUserStatus(UserStatus.enabled).build();
      UserInfoPage modelPage = userRead.findUserPageByReq(request);
      responseObserver.onNext(modelPage);
      responseObserver.onCompleted();
    } catch (Exception ex) {
      ThrowUtil.onError(log, responseObserver, ex);
    }
  }

  @Override
  @RequiresPermissions("rbac:user:add")
  public void createUser(UserCreateReq request, StreamObserver<UserModel> responseObserver) {
    String unifiedId = "";
    if (request.getCreatePlatformUser() && StringUtils.isNotBlank(request.getPlatformTenant())) {
      try (UserWrite userWrite = RbacFactory.getUserWrite(request.getPlatformTenant())) {
        UserEntity unifiedUser = userWrite.insert(unifiedId, request);
        if (null != unifiedUser) {
          unifiedId = UUIDUtil.uuid32(unifiedUser.getUserId());
        }
      } catch (Exception ex) {
        ThrowUtil.onError(log, responseObserver, ex);
      }
    }
    try (UserWrite userWrite = RbacFactory.getUserWrite(request.getTenant())) {
      UserEntity entity = userWrite.insert(unifiedId, request);
      UserModel model = UserMapper.INSTANCE.model(entity);
      responseObserver.onNext(model);
      responseObserver.onCompleted();
    } catch (Exception ex) {
      ThrowUtil.onError(log, responseObserver, ex);
    }
  }

  @Override
  @RequiresPermissions("rbac:user:update")
  public void updateUser(UserUpdateReq request, StreamObserver<UserModel> responseObserver) {
    try (UserWrite userWrite = RbacFactory.getUserWrite(request.getTenant())) {
      UserEntity entity = userWrite.update(request);
      UserModel model = UserMapper.INSTANCE.model(entity);
      responseObserver.onNext(model);
      responseObserver.onCompleted();
    } catch (Exception ex) {
      ThrowUtil.onError(log, responseObserver, ex);
    }
  }

  @Override
  @RequiresPermissions("rbac:user:delete")
  public void deleteUser(UserKey request, StreamObserver<UserModel> responseObserver) {
    try (UserWrite userWrite = RbacFactory.getUserWrite(request.getTenant())) {
      UserEntity entity = userWrite.delete(UUIDUtil.fromString(request.getUserId()));
      UserModel model = UserMapper.INSTANCE.model(entity);
      responseObserver.onNext(model);
      responseObserver.onCompleted();
    } catch (Exception ex) {
      ThrowUtil.onError(log, responseObserver, ex);
    }
  }

  @Override
  @RequiresPermissions("rbac:user:delete")
  public void batchDeleteUser(UserKeyList request, StreamObserver<Int32Value> responseObserver) {
    try (UserWrite userWrite = RbacFactory.getUserWrite(request.getTenant())) {
      final Set<UUID> set = request.getUserIdList().stream().map(v -> UUIDUtil.fromString(v))
          .collect(Collectors.toSet());

      int r = userWrite.batchDelete(set);
      responseObserver.onNext(Int32Value.of(r));
      responseObserver.onCompleted();
    } catch (Exception ex) {
      ThrowUtil.onError(log, responseObserver, ex);
    }
  }

  @Override
  @RequiresPermissions("rbac:user:import")
  public void importUser(UserImportReq request, StreamObserver<StringValue> responseObserver) {
    try (UserWrite userWrite = RbacFactory.getUserWrite(request.getTenant())) {
      String r = userWrite.importUser(request);
      responseObserver.onNext(StringValue.of(r));
      responseObserver.onCompleted();
    } catch (Exception ex) {
      ThrowUtil.onError(log, responseObserver, ex);
    }
  }

  @Override
  @RequiresPermissions("rbac:user:update")
  public void approvedUser(ApprovedUserReq request, StreamObserver<Int32Value> responseObserver) {
    try (UserWrite userWrite = RbacFactory.getUserWrite(request.getTenant())) {
      final Set<UUID> userIds = request.getUserIdList().stream().map(v -> UUIDUtil.fromString(v))
          .collect(Collectors.toSet());
      Integer r = userWrite.approvedUser(userIds, request.getApproved());
      responseObserver.onNext(Int32Value.of(r));
      responseObserver.onCompleted();
    } catch (Exception ex) {
      ThrowUtil.onError(log, responseObserver, ex);
    }
  }

  @Override
  @RequiresAuthentication
  public void assignUser(UserRoleReq request, StreamObserver<Int32Value> responseObserver) {
    try (RoleWrite roleWrite = RbacFactory.getRoleWrite(request.getTenant())) {
      UUID userId = UUIDUtil.fromString(request.getUserId());
      Set<String> roleCodes = request.getRoleCodesList().stream().collect(Collectors.toSet());
      Integer count = roleWrite.assignUser(userId, roleCodes);
      responseObserver.onNext(Int32Value.of(count));
      responseObserver.onCompleted();
    } catch (Exception ex) {
      ThrowUtil.onError(log, responseObserver, ex);
    }
  }

  @Override
  @RequiresAuthentication
  public void deassignUser(UserRoleReq request, StreamObserver<Int32Value> responseObserver) {
    try (RoleWrite roleWrite = RbacFactory.getRoleWrite(request.getTenant())) {
      UUID userId = UUIDUtil.fromString(request.getUserId());
      Set<String> roleCodes = request.getRoleCodesList().stream().collect(Collectors.toSet());
      Integer count = roleWrite.deassignUser(userId, roleCodes);
      responseObserver.onNext(Int32Value.of(count));
      responseObserver.onCompleted();
    } catch (Exception ex) {
      ThrowUtil.onError(log, responseObserver, ex);
    }
  }

  @Override
  @RequiresAuthentication
  public void existUser(VerifyUserReq request, StreamObserver<BoolValue> responseObserver) {
    try (UserRead userRead = RbacFactory.getUserRead(request.getTenant())) {
      boolean r = userRead.existUserName(request);
      responseObserver.onNext(BoolValue.of(r));
      responseObserver.onCompleted();
    } catch (Exception ex) {
      ThrowUtil.onError(log, responseObserver, ex);
    }
  }

  @Override
  @RequiresPermissions("rbac:user:import")
  public void downloadUserTemplate(TenantReq request, StreamObserver<HttpBody> responseObserver) {
    try (UserRead userRead = RbacFactory.getUserRead(request.getTenant())) {
      String realFileSrc = userRead.downloadUserTemplate(request);
      FileServiceUtil.downloadFile(responseObserver, realFileSrc);
    } catch (Exception ex) {
      ThrowUtil.onError(log, responseObserver, ex);
    }
  }

  @Override
  @RequiresPermissions("rbac:user:export")
  public void exportUser(UserExportReq request, StreamObserver<HttpBody> responseObserver) {
    try (UserRead userRead = RbacFactory.getUserRead(request.getTenant())) {
      String realFileSrc = userRead.exportUser(request);
      FileServiceUtil.downloadFile(responseObserver, realFileSrc);
    } catch (Exception ex) {
      ThrowUtil.onError(log, responseObserver, ex);
    }
  }

  @Override
  @RequiresPermissions("rbac:user:print")
  public void printUser(UserExportReq request, StreamObserver<HttpBody> responseObserver) {
    try (UserRead userRead = RbacFactory.getUserRead(request.getTenant())) {
      String realFileSrc = userRead.printUser(request);
      FileServiceUtil.downloadFile(responseObserver, realFileSrc);
    } catch (Exception ex) {
      ThrowUtil.onError(log, responseObserver, ex);
    }
  }

  @Override
  @RequiresPermissions("rbac:user:lock")
  public void lockUser(LockUserReq request, StreamObserver<Int32Value> responseObserver) {
    try (UserWrite userWrite = RbacFactory.getUserWrite(request.getTenant())) {
      final Set<UUID> set = request.getUserIdList().stream().map(v -> UUIDUtil.fromString(v))
          .collect(Collectors.toSet());
      int r = userWrite.lockUser(set, request.getLock() ? UserStatus.disabled : UserStatus.enabled);
      responseObserver.onNext(Int32Value.of(r));
      responseObserver.onCompleted();
    } catch (Exception ex) {
      ThrowUtil.onError(log, responseObserver, ex);
    }
  }

  @Override
  @RequiresPermissions("rbac:user:enable")
  public void enableUser(UserEnableKey request, StreamObserver<BoolValue> responseObserver) {
    try (UserWrite userWrite = RbacFactory.getUserWrite(request.getTenant())) {
      boolean result = userWrite.enableUser(request);
      responseObserver.onNext(BoolValue.of(result));
      responseObserver.onCompleted();
    } catch (Exception ex) {
      ThrowUtil.onError(log, responseObserver, ex);
    }
  }

  @RequiresPermissions("rbac:user:enable")
  public void batchEnableUser(EnableUserReq request, StreamObserver<Int32Value> responseObserver) {
    try (UserWrite userWrite = RbacFactory.getUserWrite(request.getTenant())) {
      final Set<UUID> set = request.getUserIdList().stream().map(v -> UUIDUtil.fromString(v))
          .collect(Collectors.toSet());
      int result = userWrite.batchEnableUser(set, request.getEnabled());
      responseObserver.onNext(Int32Value.of(result));
      responseObserver.onCompleted();
    } catch (Exception ex) {
      ThrowUtil.onError(log, responseObserver, ex);
    }
  }

  @Override
  @RequiresPermissions("rbac:user:reset")
  public void resetPwd(UserResetPwdReq request, StreamObserver<BoolValue> responseObserver) {
    try (UserWrite userWrite = RbacFactory.getUserWrite(request.getTenant())) {
      boolean r = userWrite.resetPwd(UUIDUtil.fromString(request.getUserId()), request.getPwd(),
          request.getRepeatPwd());
      responseObserver.onNext(BoolValue.of(r));
      responseObserver.onCompleted();
    } catch (Exception ex) {
      ThrowUtil.onError(log, responseObserver, ex);
    }
  }

  @Override
  @RequiresPermissions("rbac:user_log:list")
  public void findUserLogPage(UserLogReq request, StreamObserver<UserLogPage> responseObserver) {
    try (UserLogRead userLogRead = RbacFactory.getUserLogRead(request.getTenant())) {
      DtoPage<UserLogEntity, DtoTotal> page = userLogRead.findPageByReq(request);
      UserLogPage modelPage = UserLogMapper.INSTANCE.pageUserLog(page);
      responseObserver.onNext(modelPage);
      responseObserver.onCompleted();
    } catch (Exception ex) {
      ThrowUtil.onError(log, responseObserver, ex);
    }
  }

  @Override
  @RequiresPermissions("rbac:user_log:list")
  public void findUserLogList(UserLogReq request, StreamObserver<UserLogList> responseObserver) {
    try (UserLogRead userLogRead = RbacFactory.getUserLogRead(request.getTenant())) {
      List<UserLogEntity> list = userLogRead.findListByReq(request);
      List<UserLogModel> modelList = UserLogMapper.INSTANCE.listUserLog(list);
      responseObserver.onNext(UserLogList.newBuilder().addAllResults(modelList).build());
      responseObserver.onCompleted();
    } catch (Exception ex) {
      ThrowUtil.onError(log, responseObserver, ex);
    }
  }

  @Override
  @RequiresPermissions("rbac:user_log:view")
  public void findUserLogById(UserLogKey request, StreamObserver<UserLogModel> responseObserver) {
    try (UserLogRead userLogRead = RbacFactory.getUserLogRead(request.getTenant())) {
      UserLogPk pk = UserLogMapper.INSTANCE.pk(request);
      UserLogEntity entity = userLogRead.findById(pk);
      UserLogModel model = UserLogMapper.INSTANCE.model(entity);
      responseObserver.onNext(model);
      responseObserver.onCompleted();
    } catch (Exception ex) {
      ThrowUtil.onError(log, responseObserver, ex);
    }
  }

  @Override
  @RequiresPermissions("rbac:user_log:delete")
  public void deleteUserLog(UserLogDelReq request, StreamObserver<Int32Value> responseObserver) {
    try (UserLogWrite userLogWrite = RbacFactory.getUserLogWrite(request.getTenant())) {
      int r = userLogWrite.batchDelete(request.getNumber());
      responseObserver.onNext(Int32Value.of(r));
      responseObserver.onCompleted();
    } catch (Exception ex) {
      ThrowUtil.onError(log, responseObserver, ex);
    }
  }

  @Override
  @RequiresPermissions("rbac:user_log:export")
  public void exportUserLog(UserLogExportReq request, StreamObserver<HttpBody> responseObserver) {
    try (UserLogRead userLogRead = RbacFactory.getUserLogRead(request.getTenant())) {
      String realFileSrc = userLogRead.exportUserLog(request);
      FileServiceUtil.downloadFile(responseObserver, realFileSrc);
    } catch (Exception ex) {
      ThrowUtil.onError(log, responseObserver, ex);
    }
  }

  @Override
  @RequiresAuthentication
  public void getUserDeptInfo(UserKey req, StreamObserver<UserDeptJobInfoRes> responseObserver) {
    JmashPrincipal p = GrpcContext.getPrincipal();
    String tenant = req.getTenant();
    if (req.getUnified() && TenantUtil.hasTenantIdentifier(tenant)) {
      tenant = p.getTenant();
    }
    try (UserRead userRead = RbacFactory.getUserRead(tenant)) {
      UserDeptJobInfoRes userDeptInfo = userRead.getUserDeptInfo(req);
      responseObserver.onNext(userDeptInfo);
      responseObserver.onCompleted();
      return;
    } catch (Exception ex) {
      ThrowUtil.onError(log, responseObserver, ex);
    }
  }

  @Override
  public void miniAppLogin(MiniAppLoginReq request,
      StreamObserver<MiniAppLoginResp> responseObserver) {
    try (UserWrite userWrite = RbacFactory.getUserWrite(request.getTenant());
        OpensRead opensRead = RbacFactory.getOpensRead(request.getTenant())) {
      MiniLoginResp openidResp = MiniappUtil.getUserOpenId(request);
      TokenEntity tokenEntity = userWrite.loginByOpenId(request.getTenant(), OpensType.wechat,
          request.getAppId(), openidResp.getOpenid(), openidResp.getUnionid(), true, null);
      if (tokenEntity == null) {
        // 尚未注册绑定用户.
        responseObserver.onNext(MiniAppLoginResp.newBuilder().setMessage("unregistered").build());
      } else {
        // 登录Token
        MiniAppLoginResp.Builder resp = MiniAppLoginResp.newBuilder();
        TokenResp tokenResp = RbacMapper.INSTANCE.model(tokenEntity);
        responseObserver.onNext(resp.setStatus(true).setToken(tokenResp).build());
      }
      responseObserver.onCompleted();
    } catch (JmashAuthenticationException ex) {
      responseObserver.onNext(MiniAppLoginResp.newBuilder().setMessage(ex.getMessage()).build());
      responseObserver.onCompleted();
    } catch (Exception ex) {
      ThrowUtil.onError(log, responseObserver, ex);
    }
  }

  @Override
  public void miniAppPhoneNumber(MiniAppPhoneNumberReq request,
      StreamObserver<MiniAppLoginResp> responseObserver) {
    try (UserWrite userWrite = RbacFactory.getUserWrite(request.getTenant());
        UserRead userRead = RbacFactory.getUserRead(request.getTenant());
        OpenAppRead openAppRead = RbacFactory.getOpenAppRead(request.getTenant())) {
      MiniLoginResp miniLoginResp = MiniappUtil.getMiniLoginResp(request);
      PhoneInfo phoneResp = MiniappUtil.getPhoneNumber(request);
      // 先openid登录.
      TokenEntity tokenEntity = userWrite.loginByOpenId(request.getTenant(), OpensType.wechat,
          request.getAppId(), miniLoginResp.getOpenid(), miniLoginResp.getUnionid(), true,
          phoneResp.getPhoneNumber());
      // 未注册情况下,注册用户并绑定
      if (tokenEntity == null) {
        UserOpenCreateReq userCreateReq =
            MiniappUtil.getCreateUserInfo(request, phoneResp, miniLoginResp);
        tokenEntity = userWrite.createBindLogin(userCreateReq);
      }
      // 登录信息返回
      MiniAppLoginResp.Builder resp = MiniAppLoginResp.newBuilder();
      TokenResp tokenResp = RbacMapper.INSTANCE.model(tokenEntity);
      responseObserver.onNext(resp.setStatus(true).setToken(tokenResp).build());
      responseObserver.onCompleted();
    } catch (JmashAuthenticationException ex) {
      responseObserver.onNext(MiniAppLoginResp.newBuilder().setMessage(ex.getMessage()).build());
      responseObserver.onCompleted();
    } catch (Exception ex) {
      ThrowUtil.onError(log, responseObserver, ex);
    }
  }

  @Override
  @RequiresAuthentication
  public void miniAppBindPhone(MiniAppBindPhoneReq request,
      StreamObserver<BoolValue> responseObserver) {
    try (UserWrite userWrite = RbacFactory.getUserWrite(request.getTenant());
        UserRead userRead = RbacFactory.getUserRead(request.getTenant())) {
      // 获取手机号信息.
      MiniAppPhoneNumberReq phoneReq =
          MiniAppPhoneNumberReq.newBuilder().setComponentAppid(request.getComponentAppid())
              .setAppId(request.getAppId()).setPhoneCode(request.getPhoneCode()).build();
      PhoneInfo phoneResp = MiniappUtil.getPhoneNumber(phoneReq);
      String phone = phoneResp.getPurePhoneNumber();
      // 验证手机号是否存在.
      VerifyUserReq req =
          VerifyUserReq.newBuilder().setDirectoryId(new UserOpenCreateReq().getDirectoryId())
              .setTenant(request.getTenant()).setUserName(phone).build();
      if (userRead.existUserName(req)) {
        throw new ParamsValidationException("phoneCode", "手机号已绑定!");
      }
      // 更新绑定手机号.
      boolean result = userWrite.updateBindPhone(phone);
      responseObserver.onNext(BoolValue.of(result));
      responseObserver.onCompleted();
    } catch (Exception ex) {
      ThrowUtil.onError(log, responseObserver, ex);
    }
  }

  @Override
  @RequiresAuthentication
  public void loginOrgan(StringValue request, StreamObserver<TokenResp> responseObserver) {
    try (UserWrite userWrite = RbacFactory.getUserWrite(request.getValue())) {
      // 创建组织系统用户
      userWrite.createOrganSystemUser();
      // 登录组织.
      TokenEntity tokenEntity = userWrite.loginOrgan(request.getValue());
      TokenResp tokenResp = RbacMapper.INSTANCE.model(tokenEntity);
      responseObserver.onNext(tokenResp);
      responseObserver.onCompleted();
    } catch (Exception ex) {
      ThrowUtil.onError(log, responseObserver, ex);
    }
  }

  @Override
  @RequiresAuthentication
  public void createOrganUser(OrganUserCreateReq request,
      StreamObserver<UserModel> responseObserver) {
    JmashPrincipal principal = GrpcContext.getPrincipal();
    try (UserRead userRead = RbacFactory.getUserRead(principal.getTenant());
        UserWrite userWrite = RbacFactory.getUserWrite(request.getOrganTenant())) {
      UserEntity user = new UserEntity();
      if (request.getManager()) {
        user = userWrite.createOrganUser(request);
      } else {
        UserEntity unifiedUser = userRead.findById(principal.getNameUUID());
        user = userWrite.createOrganUser(unifiedUser, request);
      }
      UserModel model = UserMapper.INSTANCE.model(user);
      responseObserver.onNext(model);
      responseObserver.onCompleted();
    } catch (Exception ex) {
      ThrowUtil.onError(log, responseObserver, ex);
    }
  }

  /**
   * 扫码创建用户，无需权限
   */
  @Override
  public void createUserByQrcode(ScanCodeCreateUserReq request,
      StreamObserver<TokenResp> responseObserver) {
    try (UserWrite userWrite = RbacFactory.getUserWrite(request.getTenant())) {
      // 创建用户并登录
      TokenEntity tokenEntity = userWrite.createUserByQrcode(request);
      responseObserver.onNext(RbacMapper.INSTANCE.model(tokenEntity));
      responseObserver.onCompleted();
    } catch (Exception ex) {
      ThrowUtil.onError(log, responseObserver, ex);
    }
  }

  @Override
  public void mobileAppLogin(MobileAppLoginReq request,
      StreamObserver<MobileAppLoginResp> responseObserver) {
    try (UserWrite userWrite = RbacFactory.getUserWrite(request.getTenant())) {
      MobileAppUserOpenIdResp openidResp = MobileAppUtil.getUserOpenId(request);
      TokenEntity tokenEntity = userWrite.loginByOpenId(request.getTenant(), OpensType.wechat,
          request.getAppId(), openidResp.getOpenId(), openidResp.getUnionId(), true, null);
      if (tokenEntity == null) {
        // 缓存openid
        String cacheKey = MobileAppUtil.cacheOpenId(openidResp);
        // 尚未注册绑定用户.
        responseObserver.onNext(MobileAppLoginResp.newBuilder().setCacheKey(cacheKey)
            .setMessage("unregistered").build());
      } else {
        // 登录Token
        MobileAppLoginResp.Builder resp = MobileAppLoginResp.newBuilder();
        TokenResp tokenResp = RbacMapper.INSTANCE.model(tokenEntity);
        responseObserver.onNext(resp.setStatus(true).setToken(tokenResp).build());
      }
      responseObserver.onCompleted();
    } catch (JmashAuthenticationException ex) {
      responseObserver.onNext(MobileAppLoginResp.newBuilder().setMessage(ex.getMessage()).build());
      responseObserver.onCompleted();
    } catch (Exception ex) {
      ThrowUtil.onError(log, responseObserver, ex);
    }
  }

  @Override
  public void mobileAppLoginBindPhone(MobileAppLoginBindPhoneReq request,
      StreamObserver<MobileAppLoginResp> responseObserver) {
    try (UserWrite userWrite = RbacFactory.getUserWrite(request.getTenant())) {
      // 校验验证码是否正确
      if (!VerifyCodeUtil.validate(request.getPhoneNumber(), request.getVerifyCode())) {
        responseObserver
            .onNext(MobileAppLoginResp.newBuilder().setMessage("验证码输入错误,请重新输入!").build());
        responseObserver.onCompleted();
        return;
      }
      // 查询缓存的openId、unionId
      MobileAppUserOpenIdResp openIdResp = MobileAppUtil.getCacheOpenId(request.getCacheKey());
      if (openIdResp == null) {
        responseObserver
            .onNext(MobileAppLoginResp.newBuilder().setMessage("微信授权已失效，请重新授权！").build());
        responseObserver.onCompleted();
        return;
      }
      // 先openid登录.
      TokenEntity tokenEntity =
          userWrite.loginByOpenId(request.getTenant(), OpensType.wechat, request.getAppId(),
              openIdResp.getOpenId(), openIdResp.getUnionId(), true, request.getPhoneNumber());
      // 未注册情况下,注册用户并绑定
      if (tokenEntity == null) {
        UserOpenCreateReq userCreateReq = MobileAppUtil.getCreateUserInfo(request, openIdResp);
        tokenEntity = userWrite.createBindLogin(userCreateReq);
      }
      // 登录信息返回
      MobileAppLoginResp.Builder resp = MobileAppLoginResp.newBuilder();
      TokenResp tokenResp = RbacMapper.INSTANCE.model(tokenEntity);
      responseObserver.onNext(resp.setStatus(true).setToken(tokenResp).build());
      responseObserver.onCompleted();
    } catch (JmashAuthenticationException ex) {
      responseObserver.onNext(MobileAppLoginResp.newBuilder().setMessage(ex.getMessage()).build());
      responseObserver.onCompleted();
    } catch (Exception ex) {
      ThrowUtil.onError(log, responseObserver, ex);
    }
  }

  @Override
  public void loginGzhAuthUrl(LoginGzhAuthUrlReq req,
      StreamObserver<StringValue> responseObserver) {
    try {
      String redirectUrl =
          getRedirectUrl(req.getRedirectUri(), req.getTenant(), req.getComponentAppid());
      String authorizeUrl = OauthWechatClient.generateRedirectURI(req.getComponentAppid(),
          req.getAppId(), redirectUrl, "snsapi_base", req.getState());
      responseObserver.onNext(StringValue.of(authorizeUrl));
      responseObserver.onCompleted();
    } catch (Exception ex) {
      ThrowUtil.onError(log, responseObserver, ex);
    }
  }

  @Override
  public void loginGzhAuth(LoginGzhAuthReq req, StreamObserver<LoginGzhAuthResp> responseObserver) {
    try (UserWrite userWrite = RbacFactory.getUserWrite(req.getTenant())) {
      // 获取用户公众号OpenId
      OauthCodeReq codeReq = OauthCodeReq.newBuilder().setTenant(req.getTenant())
          .setComponentAppid(req.getComponentAppid()).setAuthorizerAppid(req.getAppId())
          .setCode(req.getCode()).build();
      OauthUserOpenIdResp resp = WechatClient.getWechatBlockingStub().findOauthUserOpenId(codeReq);
      // 登录
      TokenEntity token = userWrite.loginByOpenId(req.getTenant(), OpensType.wechat, req.getAppId(),
          resp.getOpenId(), resp.getUnionId(), false, null);
      LoginGzhAuthResp.Builder respBuilder = LoginGzhAuthResp.newBuilder();
      if (token != null) {
        // 登录成功
        TokenResp tokenResp = RbacMapper.INSTANCE.model(token);
        responseObserver.onNext(respBuilder.setStatus(true).setToken(tokenResp).build());
      } else {
        // 准备注册，获取微信用户信息
        String redirectUrl =
            getRedirectUrl(req.getRedirectUri(), req.getTenant(), req.getComponentAppid());
        String authorizeUrl = OauthWechatClient.generateRedirectURI(req.getComponentAppid(),
            req.getAppId(), redirectUrl, "snsapi_userinfo", req.getState());
        responseObserver
            .onNext(respBuilder.setStatus(false).setUserInfoAuthUrl(authorizeUrl).build());
      }
      responseObserver.onCompleted();
    } catch (Exception ex) {
      ThrowUtil.onError(log, responseObserver, ex);
    }
  }

  @Override
  public void loginGzhRegister(LoginGzhRegisterReq req,
      StreamObserver<LoginGzhRegisterResp> responseObserver) {
    try (UserWrite userWrite = RbacFactory.getUserWrite(req.getTenant())) {
      // 1.判断验证码是否正确
      if (StringUtils.isNotBlank(req.getName())
          && !VerifyCodeUtil.validate(req.getName(), req.getValidCode())) {
        responseObserver.onError(Status.INTERNAL.withDescription("验证码输入不正确,请重新获取!").asException());
        return;
      }
      // 获取公众号用户信息.
      OauthCodeReq codeReq = OauthCodeReq.newBuilder().setTenant(req.getTenant())
          .setComponentAppid(req.getComponentAppid()).setAuthorizerAppid(req.getAppId())
          .setCode(req.getCode()).build();
      OauthUserInfoResp userInfo = WechatClient.getWechatBlockingStub().findOauthUserInfo(codeReq);
      // Union登录
      TokenEntity token = userWrite.createUserByGzh(req.getTenant(), req.getName(), "user",
          req.getAppId(), userInfo);
      LoginGzhRegisterResp.Builder respBuilder = LoginGzhRegisterResp.newBuilder();
      if (token != null) {
        // 登录成功
        TokenResp tokenResp = RbacMapper.INSTANCE.model(token);
        responseObserver.onNext(respBuilder.setStatus(true).setToken(tokenResp).build());
      } else {
        responseObserver.onNext(respBuilder.setStatus(false).setMessage("").build());
      }
      responseObserver.onCompleted();
    } catch (Exception ex) {
      ThrowUtil.onError(log, responseObserver, ex);
    }
  }

  // 微信回调地址
  public String getRedirectUrl(String redirectUri, String tenant, String componentAppId) {
    String url = String.format("%s/%s/%s", redirectUri, tenant, componentAppId);
    log.info("RedirectUrl:" + url);
    return url;
  }

  @Override
  public void loginAliAuth(LoginAliAuthReq req, StreamObserver<LoginTokenResp> responseObserver) {
    try (UserWrite userWrite = RbacFactory.getUserWrite(req.getTenant())) {
      // 获取openId
      AlipaySystemOauthTokenResponse resp =
          AlipayUtil.userOpenId(req.getTenant(), req.getAppId(), req.getAuthCode());
      if (!resp.isSuccess()) {
        responseObserver.onError(
            Status.INTERNAL.withDescription("支付宝回调失败，code不合法！" + req.getAuthCode()).asException());
        return;
      }
      log.warn(resp);
      String openId =
          StringUtils.isNotBlank(resp.getUserId()) ? resp.getUserId() : resp.getOpenId();
      TokenEntity token = userWrite.loginByOpenId(req.getTenant(), OpensType.ali_pay,
          req.getAppId(), openId, resp.getUnionId(), false, null);
      LoginTokenResp.Builder respBuilder = LoginTokenResp.newBuilder();
      if (token != null) {
        // 登录成功
        TokenResp tokenResp = RbacMapper.INSTANCE.model(token);
        responseObserver.onNext(respBuilder.setStatus(true).setToken(tokenResp).build());
      } else {
        responseObserver.onNext(respBuilder.setStatus(false).build());
      }
      responseObserver.onCompleted();
    } catch (Exception ex) {
      ThrowUtil.onError(log, responseObserver, ex);
    }
  }

  @Override
  public void loginAliRegister(LoginAliRegisterReq req,
      StreamObserver<LoginTokenResp> responseObserver) {
    try (UserWrite userWrite = RbacFactory.getUserWrite(req.getTenant())) {
      // 1.判断验证码是否正确
      if (StringUtils.isNotBlank(req.getName())
          && !VerifyCodeUtil.validate(req.getName(), req.getValidCode())) {
        responseObserver.onError(Status.INTERNAL.withDescription("验证码输入不正确,请重新获取!").asException());
        return;
      }
      AlipaySystemOauthTokenResponse resp =
          AlipayUtil.userOpenId(req.getTenant(), req.getAppId(), req.getAuthCode());
      if (!resp.isSuccess()) {
        responseObserver.onError(
            Status.INTERNAL.withDescription("支付宝回调失败，code不合法！" + req.getAuthCode()).asException());
        return;
      }
      log.warn(resp);
      // 获取用户并注册用户
      AlipayUserInfoShareResponse userInfo =
          AlipayUtil.userInfo(req.getTenant(), req.getAppId(), resp.getAccessToken());

      TokenEntity token = userWrite.createUserByAlipay(req.getTenant(), req.getName(), "user",
          req.getAppId(), resp, userInfo);
      LoginTokenResp.Builder respBuilder = LoginTokenResp.newBuilder();
      if (token != null) {
        // 登录成功
        TokenResp tokenResp = RbacMapper.INSTANCE.model(token);
        responseObserver.onNext(respBuilder.setStatus(true).setToken(tokenResp).build());
      } else {
        responseObserver.onNext(respBuilder.setStatus(false).setMessage("").build());
      }
      responseObserver.onCompleted();
    } catch (Exception ex) {
      ThrowUtil.onError(log, responseObserver, ex);
    }
  }

  @Override
  public void loginUnionPayAuth(LoginUnionPayReq req,
      StreamObserver<LoginTokenResp> responseObserver) {
    try (UserWrite userWrite = RbacFactory.getUserWrite(req.getTenant())) {
      // 获取openId
      UnionTokenResp resp =
          unionPayService.userToken(req.getTenant(), req.getAppId(), req.getCode());
      if (!resp.isSuccess()) {
        responseObserver.onError(
            Status.INTERNAL.withDescription("云闪付回调失败，code不合法！" + req.getCode()).asException());
        return;
      }
      log.warn(resp);
      TokenEntity token = userWrite.loginByOpenId(req.getTenant(), OpensType.union_pay,
          req.getAppId(), resp.getParams().getOpenId(), resp.getParams().getUnionId(), true, null);
      LoginTokenResp.Builder respBuilder = LoginTokenResp.newBuilder();
      if (token != null) {
        // 登录成功
        TokenResp tokenResp = RbacMapper.INSTANCE.model(token);
        responseObserver.onNext(respBuilder.setStatus(true).setToken(tokenResp).build());
      } else {
        responseObserver.onNext(respBuilder.setStatus(false).build());
      }
      responseObserver.onCompleted();
    } catch (Exception ex) {
      ThrowUtil.onError(log, responseObserver, ex);
    }
  }

  @Override
  public void loginUnionPayRegister(LoginUnionPayRegisterReq req,
      StreamObserver<LoginTokenResp> responseObserver) {
    try (UserWrite userWrite = RbacFactory.getUserWrite(req.getTenant())) {
      // 获取openId
      UnionUserMobile resp =
          unionPayService.userMobile(req.getTenant(), req.getAppId(), req.getCode());
      log.warn(resp);
      TokenEntity token = userWrite.loginByOpenId(req.getTenant(), OpensType.union_pay,
          req.getAppId(), resp.getOpenId(), null, true, resp.getMobile());
      if (token == null) {
        token = userWrite.createUserByUnionPay(req.getTenant(), "user", req.getAppId(), resp);
      }
      LoginTokenResp.Builder respBuilder = LoginTokenResp.newBuilder();
      if (token != null) {
        // 登录成功
        TokenResp tokenResp = RbacMapper.INSTANCE.model(token);
        responseObserver.onNext(respBuilder.setStatus(true).setToken(tokenResp).build());
      } else {
        responseObserver.onNext(respBuilder.setStatus(false).setMessage("").build());
      }
      responseObserver.onCompleted();
    } catch (Exception ex) {
      ThrowUtil.onError(log, responseObserver, ex);
    }
  }

  @Override
  public void appendRolePerm(AppendRolePermReq req, StreamObserver<BoolValue> responseObserver) {
    try (RoleWrite roleWrite = RbacFactory.getRoleWrite(req.getTenant())) {
      boolean value = roleWrite.appendRolePerm(req);
      responseObserver.onNext(BoolValue.of(value));
      responseObserver.onCompleted();
    } catch (Exception ex) {
      ThrowUtil.onError(log, responseObserver, ex);
    }
  }

  @Override
  @RequiresAuthentication
  public void checkGzhSubscribe(GzhSubscribeCheckReq request,
      StreamObserver<BoolValue> responseObserver) {
    try (RoleWrite roleWrite = RbacFactory.getRoleWrite(request.getTenant());
        OpensRead opensRead = RbacFactory.getOpensRead(request.getTenant())) {
      UUID userId = GrpcContext.getPrincipal().getNameUUID();
      List<String> unionIds = opensRead.findOpensUnionId(userId);
      boolean value = MiniappUtil.checkSubscribe(request, unionIds);
      responseObserver.onNext(BoolValue.of(value));
      responseObserver.onCompleted();
    } catch (Exception ex) {
      ThrowUtil.onError(log, responseObserver, ex);
    }
  }

  // 客户端登录无需权限.
  @Override
  public void loginApp(LoginAppReq req, StreamObserver<LoginTokenResp> responseObserver) {
    // 用户登录.
    try (RoleRead roleRead = RbacFactory.getRoleRead(req.getTenant());
        UserWrite userWrite = RbacFactory.getUserWrite(req.getTenant())) {
      TokenEntity token = userWrite.loginApp(req);
      LoginTokenResp.Builder respBuilder = LoginTokenResp.newBuilder();
      if (token != null) {
        // 登录成功
        TokenResp tokenResp = RbacMapper.INSTANCE.model(token);
        responseObserver.onNext(respBuilder.setStatus(true).setToken(tokenResp).build());
      } else {
        responseObserver.onNext(respBuilder.setStatus(false).setMessage("客户端ID或密钥错误!").build());
      }
      responseObserver.onCompleted();
    } catch (Exception ex) {
      ThrowUtil.onError(log, responseObserver, ex);
    }
  }

  // 添加组织用户
  @Override
  @RequiresPermissions("rbac:user:add")
  public void addOrganUser(OrganUserAddReq request, StreamObserver<UserModel> responseObserver) {
    try (UserRead userRead = RbacFactory.getUserRead(request.getPlatformTenant());
        UserWrite userWrite = RbacFactory.getUserWrite(request.getTenant())) {
      UserEntity unifiedUser = userRead.findById(UUIDUtil.fromString(request.getUserId()));
      // 创建组织用户.
      OrganUserCreateReq.Builder req = OrganUserCreateReq.newBuilder();
      req.setRequestId(request.getRequestId()).setValidateOnly(request.getValidateOnly());
      req.setOrganTenant(request.getTenant()).setDirectoryId(request.getDirectoryId());
      UserEntity user = userWrite.createOrganUser(unifiedUser, req.build());
      // 添加用户到组织.
      String organId = TenantUtil.getTenantIdentifierStr(request.getTenant());
      StorageOrganUserCreateReq.Builder storage = StorageOrganUserCreateReq.newBuilder();
      storage.setRequestId(UUID.randomUUID().toString()).setTenant(request.getPlatformTenant());
      storage.setOrganId(organId).setUnifiedId(user.getUnifiedId());
      StorageClient.getStorageBlockingStub().createStorageOrganUser(storage.build());
      UserModel model = UserMapper.INSTANCE.model(user);
      responseObserver.onNext(model);
      responseObserver.onCompleted();
    } catch (Exception ex) {
      ThrowUtil.onError(log, responseObserver, ex);
    }
  }

}
